I'm working through a "hello world" tutorial on Asp.Net Core. I'm using WebApi (not MVC).
Here is the controller for the REST API I'm trying to invoke:
...
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class ManageCarController : ControllerBase
{
private IMapper mapper;
private ApplicationDbContext dbContext;
public ManageCarController(IMapper mapper, ApplicationDbContext dbContext)
{
this.mapper = mapper;
this.dbContext = dbContext;
}
// GET api/values
[HttpGet]
public IEnumerable<CarViewModel> Get()
{
IEnumerable<CarViewModel> list =
this.mapper.Map<IEnumerable<CarViewModel>>(this.dbContext.cars.AsEnumerable());
return list;
}
...
Here is my controller for Login:
...
[Authorize]
[Route("[controller]/[action]")]
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILogger<AccountController> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_logger = logger;
}
[TempData]
public string ErrorMessage { get; set; }
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login([FromBody]LoginViewModel model)
{
if (ModelState.IsValid)
{
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync
(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
var msg = "User logged in.";
return Ok(msg);
}
}
// If we got this far, something failed, redisplay form
return BadRequest("Fail to login with this account");
}
I can log in (http://localhost:5000/Login
) OK, the response is "User logged in."
When I browse to http://localhost:5000/api/ManageCar
, it redirects here and gives me an HTTP 404: https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar
, and I never hit the controller.
If I comment out [Authorize]
, then http://localhost:5000/api/ManageCar
works OK.
What am I missing?
More importantly, what is a good way to troubleshoot the problem?
Prior to calling http://localhost:5000/api/ManageCar
, I first log in (successfully).
Here is what I see in Edge > Developer Tools > Network:
Name Protocol Method Result Content type Received Time Initiator
https://localhost:44342/Account/Login HTTP/2 POST 200 application/json 9.31 s XMLHttpRequest
<= Login: OK
https://localhost:44342/Account/Login HTTPS GET 200 (from cache) 0 s
<= ManageCars (GET@1): OK
https://localhost:44342/api/ManageCar HTTP/2 GET 302 0 B 97.43 ms XMLHttpRequest
<= ManageCars (GET@2 - 302 redirect to REST API): OK
https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar HTTP/2 GET 404 0 B 16.77 ms XMLHttpRequest
<= ManageCars (GET@3 - 404: not found): FAILS
- Console:
HTTP 404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier).
(XHR)GET - https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar
CLARIFICATION FOR Tân Nguyễn's RESPONSE:
/api/ManageCar
. If I call with without [Authorize], it works./api/ManageCar
... it DOESN'T go directly to my controller for "/api/ManageCar".I still haven't resolved the problem - I'm still getting HTTP 404 with [Authorize]
, and it works without [Authorize]
Both my AccountController and ManageCarController have the same path: [Route("api/[controller]/[action])]' and
[Route("api/[controller])]`, respectively. I can still log in successfully, I still get HTTP 404 when I try to read the "Cars" list.
I enabled "Trace" logging in my appsettings.json
. Here is a summary of the output of the failed API call:
Console log:
- Request starting HTTP/1.1 GET http://localhost:63264/api/ManageCar
Request finished in 81.994ms 302
- Request starting HTTP/1.1 GET http://localhost:63264/Account/Login?ReturnUrl=%2Fapi%2FManageCar
AuthenticationScheme: Identity.Application was successfully authenticated.
The request path /Account/Login does not match a supported file type
The request path does not match the path filter
Request finished in 31.9471ms 404
Summary:
a) request to "ManageCar" redirects to AccountController => OK
b) AccountController gets the request => OK
c) Q: Does AccountController authenticate the request? <= it seems to ("successfully authenticated"...)
d) Q: What do "match a supported file type" or "match the path filter" mean?
What can I do about them?
I think that is a problem of routing, can you verify your routes. do you notice that the two controllers have two routes every one [Route("[controller]/[action]")] and [Route("api/[controller]")].
If your routes are OK, you should check your authentication mechanism. How do you check if user is authenticated and how to redirect because you don't need to be redirected to your login method in every Api method if you are already authenticated.
Thanks.