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
就可以了。
问:我错过了什么?
问:更重要的是,有什么好的解决问题的方法?
问:我应该提供哪些(如果有)额外信息?
提前致谢!
更新:
在调用http://localhost:5000/api/ManageCar
之前,我首先登录(成功)。
这是我在 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 的回复的澄清:
- 我有一个 REST API,使用 Asp.Net Core 2.1 + Web API 用 C# 编写。
- API 有一个 "GET" 方法,
/api/ManageCar
。如果我在没有 [Authorize] 的情况下调用,它会起作用。
- 我是 "securing" 和 Asp.Net Core Identity 的 API。 URL 是“/Account/Login”。它需要使用 POST (传递用户名和密码)。那也行。
- 如果我用 [Authorize] 注释 "ManageCar",然后登录(成功),那么 THEN GET
/api/ManageCar
... 它确实如此'直接转到我的控制器以获取“/api/ManageCar”。
- 而是转到“/Account/Login”(我已经登录,结果是 HTTP 200),然后重定向到“https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar”/
- 我 应该 能够为我的登录做一个 POST,并为我的(现在经过身份验证的)查询做一个 GET - 它 应该 "just work".
- 不幸的是,我不知道 Asp.Net 在做什么 "behind the scenes" ...而且我不知道是什么导致了问题,也不知道如何解决它。
更新
我仍然没有解决问题 - 我仍然在使用 [Authorize]
时收到 HTTP 404,并且它在没有 [Authorize]
[=88 的情况下也能正常工作=]
我的 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.
我在 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?
如果我理解你的意思是正确的,问题可能来自两件事:
- 您正试图在未登录的情况下访问
/api/ManageCar
。属性 [Authorize]
表示:此 controller/action 需要登录才能分配给。
这就是它重定向到路径的原因:/Account/Login?ReturnUrl=%2Fapi%2FManageCar
你可以查看路径,有两部分:
第一部分是:/Account/Login
。这是登录页面的url。
第二部分为:?ReturnUrl=%2Fapi%2FManageCar
。我们可以理解:?ReturnUrl=/api/ManageCar
因为%2F
代表/
。该参数查询字符串的意思是:登录成功后,请求重定向到/api/ManaCar
.
- 第二个问题可能是:在
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 方法中都重定向到您的登录方法。
谢谢。
我正在学习关于 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
就可以了。
问:我错过了什么?
问:更重要的是,有什么好的解决问题的方法?
问:我应该提供哪些(如果有)额外信息?
提前致谢!
更新:
在调用
http://localhost:5000/api/ManageCar
之前,我首先登录(成功)。这是我在 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 的回复的澄清:
- 我有一个 REST API,使用 Asp.Net Core 2.1 + Web API 用 C# 编写。
- API 有一个 "GET" 方法,
/api/ManageCar
。如果我在没有 [Authorize] 的情况下调用,它会起作用。 - 我是 "securing" 和 Asp.Net Core Identity 的 API。 URL 是“/Account/Login”。它需要使用 POST (传递用户名和密码)。那也行。
- 如果我用 [Authorize] 注释 "ManageCar",然后登录(成功),那么 THEN GET
/api/ManageCar
... 它确实如此'直接转到我的控制器以获取“/api/ManageCar”。 - 而是转到“/Account/Login”(我已经登录,结果是 HTTP 200),然后重定向到“https://localhost:44342/Account/Login?ReturnUrl=%2Fapi%2FManageCar”/
- 我 应该 能够为我的登录做一个 POST,并为我的(现在经过身份验证的)查询做一个 GET - 它 应该 "just work".
- 不幸的是,我不知道 Asp.Net 在做什么 "behind the scenes" ...而且我不知道是什么导致了问题,也不知道如何解决它。
更新
我仍然没有解决问题 - 我仍然在使用
[=88 的情况下也能正常工作=][Authorize]
时收到 HTTP 404,并且它在没有[Authorize]
我的 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.我在
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?
如果我理解你的意思是正确的,问题可能来自两件事:
- 您正试图在未登录的情况下访问
/api/ManageCar
。属性[Authorize]
表示:此 controller/action 需要登录才能分配给。
这就是它重定向到路径的原因:/Account/Login?ReturnUrl=%2Fapi%2FManageCar
你可以查看路径,有两部分:
第一部分是:
/Account/Login
。这是登录页面的url。第二部分为:
?ReturnUrl=%2Fapi%2FManageCar
。我们可以理解:?ReturnUrl=/api/ManageCar
因为%2F
代表/
。该参数查询字符串的意思是:登录成功后,请求重定向到/api/ManaCar
.- 第二个问题可能是:在
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 方法中都重定向到您的登录方法。
谢谢。