【问题标题】:ASP.Net Core 2.1/WebAPI app: "HTTP 404 not found" calling a REST url with [Authorize]ASP.Net Core 2.1/WebAPI 应用程序:“找不到 HTTP 404”使用 [Authorize] 调用 REST url
【发布时间】:2019-04-22 10:04:19
【问题描述】:

我正在学习有关 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) 好的,响应是“用户登录”。

当我浏览到 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 > 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
    

澄清 Tân Nguyễn 的回应:

  1. 我有一个 REST API,使用 Asp.Net Core 2.1 + Web API 用 C# 编写。
  2. API 有一个“GET”方法,/api/ManageCar。如果我在没有 [Authorize] 的情况下调用,它会起作用。
  3. 我正在使用Asp.Net Core Identity“保护”API。 URL 是“/帐户/登录”。它需要使用 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 - 它应该“正常工作”。
  7. 不幸的是,我不知道 Asp.Net 在“幕后”做了什么......我不知道是什么导致了问题,也不知道如何解决它。

更新

  1. 我仍然没有解决问题 - 我仍然收到带有 [Authorize] 的 HTTP 404,并且它在没有 [Authorize] 的情况下也能正常工作

  2. 我的 AccountController 和 ManageCarController 都有相同的路径:[Route("api/[controller]/[action])]' and[Route("api/[controller])]`,分别。我仍然可以成功登录,当我尝试时仍然得到 HTTP 404阅读“汽车”列表。

  3. 我在appsettings.json 中启用了“跟踪”日志记录。以下是失败的 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?
    

【问题讨论】:

  • 您的登录方法只接受 HTTP POST,但重定向将是 GET 请求。
  • @DavidG:我在调用 API 之前使用 POST 成功登录。我正在使用从 Edge > Developer Tools 获得的网络调用来更新我的帖子。
  • 问:如果我只需要一个[HttpGet](我是 Asp.Net Core 的新手——不要相信你),那我该怎么做呢?你能给我一个“回应”,指出我正确的方向吗?
  • 尝试通过将属性更改为[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)] 来指定身份验证模式。您正在尝试使用 cookie 授权 web api,如果没有其他配置,它可能会失败
  • 一般情况下,PasswordSignInAsync 用于 cookie 认证,如果你只有 web api,可能需要移动到 JWT 令牌

标签: c# asp.net-core asp.net-web-api2 identity


【解决方案1】:

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

  1. 您正在尝试访问/api/ManageCar 而无需登录。属性[Authorize] 表示:此控制器/操作需要先登录才能分配给。

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

可以查看路径,有2部分:

  • 第一部分是:/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);
});

【讨论】:

  • 谢谢。让我以不同的方式解释这个问题:请参阅上面的更新。
  • @FoggyDay 抱歉迟到了,我妈妈需要帮助 :) 在你的情况下,我只能考虑Cookie。 cookie 尚未设置。所以,登录成功后,请求仍然没有被授权
【解决方案2】:

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

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

谢谢。

【讨论】:

  • 我是“路由”的新手,还有很多我不明白的地方。例如,问:为什么 Asp.Net Core 仅仅因为 [Authorize] 而调用我的 AccountController?我没有在任何地方明确指定。它是“隐式的”。问:我是否需要在 AccountController 中执行“其他操作”才能使其正常工作?
  • 现在可以使用了。我尝试了很多很多东西,但不幸的是,我并不确切知道“是什么修复了它”。它肯定与“路由”有关。感谢您的帮助。
猜你喜欢
  • 2018-08-11
  • 2019-05-05
  • 1970-01-01
  • 1970-01-01
  • 2020-05-12
  • 1970-01-01
  • 2019-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多