ASP.Net Core 2.1/WebAPI 应用程序:"HTTP 404 not found" 使用 [Authorize] 调用 REST url

ASP.Net Core 2.1/WebAPI app: "HTTP 404 not found" calling a REST url with [Authorize]

我正在学习关于 Asp.Net Core 的 "hello world" 教程。我正在使用 WebApi(不是 MVC)。

这是 REST 的控制器 API 我正在尝试调用:

...
[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;
}
...

这是我的登录控制器:

...
[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");
    }

我可以登录(http://localhost:5000/Login) 好的,响应是"User logged in."

当我浏览到 http://localhost:5000/api/ManageCar 时,它会重定向到这里并给我一个 HTTP 404:https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar,但我从未点击过控制器。

如果我注释掉 [Authorize],那么 http://localhost:5000/api/ManageCar 就可以了。

问:我错过了什么?

问:更重要的是,有什么好的解决问题的方法?

问:我应该提供哪些(如果有)额外信息?

提前致谢!


更新:

  1. 在调用http://localhost:5000/api/ManageCar之前,我首先登录(成功)。

  2. 这是我在 Edge > 开发者工具 > 网络中看到的:

    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
    

对 Tân Nguyễn 的回复的澄清:

  1. 我有一个 REST API,使用 Asp.Net Core 2.1 + Web API 用 C# 编写。
  2. API 有一个 "GET" 方法,/api/ManageCar。如果我在没有 [Authorize] 的情况下调用,它会起作用。
  3. 我是 "securing" 和 Asp.Net Core Identity 的 API。 URL 是“/Account/Login”。它需要使用 POST (传递用户名和密码)。那也行。
  4. 如果我用 [Authorize] 注释 "ManageCar",然后登录(成功),那么 THEN GET /api/ManageCar ... 它确实如此'直接转到我的控制器以获取“/api/ManageCar”。
  5. 而是转到“/Account/Login”(我已经登录,结果是 HTTP 200),然后重定向到“https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar”/
  6. 应该 能够为我的登录做一个 POST,并为我的(现在经过身份验证的)查询做一个 GET - 它 应该 "just work".
  7. 不幸的是,我不知道 Asp.Net 在做什么 "behind the scenes" ...而且我不知道是什么导致了问题,也不知道如何解决它。

更新

  1. 我仍然没有解决问题 - 我仍然在使用 [Authorize] 时收到 HTTP 404,并且它在没有 [Authorize]

    [=88 的情况下也能正常工作=]
  2. 我的 AccountController 和 ManageCarController 都有相同的路径:[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.

  3. 我在 appsettings.json 中启用了 "Trace" 登录。以下是失败的 API 调用的输出摘要:

    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?
    

如果我理解你的意思是正确的,问题可能来自两件事:

  1. 您正试图在未登录的情况下访问 /api/ManageCar。属性 [Authorize] 表示:此 controller/action 需要登录才能分配给。

这就是它重定向到路径的原因:/Account/Login?ReturnUrl=%2Fapi%2FManageCar

你可以查看路径,有两部分:

  • 第一部分是:/Account/Login。这是登录页面的url。

  • 第二部分为:?ReturnUrl=%2Fapi%2FManageCar。我们可以理解?ReturnUrl=/api/ManageCar因为%2F代表/。该参数查询字符串的意思是:登录成功后,请求重定向到/api/ManaCar.

    1. 第二个问题可能是:在Get 方法中,您通过使用[HttpGet] 将其设置为GET 方法。这意味着此方法只能通过使用 GET 方法分配给。因此,如果您尝试发出 POST 请求,那是行不通的。

[HttpGet]
public IEnumerable<CarViewModel> Get()
{
    IEnumerable<CarViewModel> list =
        this.mapper.Map<IEnumerable<CarViewModel>>(this.dbContext.cars.AsEnumerable());
    return list;
}

如果您使用的是jquery,登录成功后,您可以尝试发出这样的GET请求:

$.get('/api/ManageCar').done(function (data) {
    console.log(data);
});

或将 [HttpGet] 属性更改为 [HttpPost] 属性:

$.post('/api/ManageCar').done(function (data) {
    console.log(data);
});

我认为是路由的问题,你能验证一下你的路由吗? 你注意到这两个控制器每一个都有两条路线吗 [Route([controller]/[action]")] 和 [Route("api/[controller]")].

如果您的路由没有问题,您应该检查您的身份验证机制。 您如何检查用户是否已通过身份验证以及如何重定向,因为如果您已经通过身份验证,则不需要在每个 Api 方法中都重定向到您的登录方法。

谢谢。