我正在尝试构建一个非常简单的游乐场服务器,以便我研究一些 ASP.NET Core 身份验证/授权概念。基本上是一个带有一个非常简单的控制器的网络应用程序,可以使用 Postman 进行测试。
我想出了我的代码的缩小版本,由一个登录端点组成,该端点将使用 Cookie 身份验证对用户进行身份验证(无需凭据),如下所示:
[ApiController]
public class MyController : ControllerBase
{
[HttpGet("/login")]
public async Task<IActionResult> Login()
{
var claims = new[] { new Claim("name", "bob") };
var identity = new ClaimsIdentity(claims);
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(principal);
return Ok();
}
}
问题是对 HttpContext.SignInAsync()
的调用引发了以下异常:
System.InvalidOperationException: SignInAsync when principal.Identity.IsAuthenticated is false is not allowed when AuthenticationOptions.RequireAuthenticatedSignIn is true.
at Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, String scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
at MyController.Login() in C:\Users\vinic\Desktop\TEMP\TestesAuthorization\Controllers\MyController.cs:line 18
然后我尝试通过调用 HttpContext.SignInAsync()
替换 HttpContext.AuthenticateAsync()
,以便在再次尝试调用 SignInAsync()
之前验证用户身份:
[HttpGet("/login")]
public async Task<IActionResult> Login()
{
var authResult = await HttpContext.AuthenticateAsync();
if (authResult.Succeeded == false)
return StatusCode(500, "Failed to autenticate!");
return Ok();
}
但在这种情况下,AuthenticateAsync()
结果总是返回一个失败 (authResult.Succeeded
= false),以后对 HttpContext.SignInAsync()
的调用将失败,并返回与之前相同的 InvalidOperationException。通过启用“跟踪”级日志记录,对 AuthenticateAsync() 的调用仅记录以下(不是很有帮助)信息:
dbug: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[9]
AuthenticationScheme: Cookies was not authenticated.
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler: Debug: AuthenticationScheme: Cookies was not authenticated.
我的项目面向 net5.0
框架,没有外部/显式依赖项,这是我正在使用的 Startup 类:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IConfiguration configs)
{
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
我知道我在这里一定遗漏了一些非常基本的东西。我也不确定我所基于的 the documentation 实际上是否适用于 .NET 5.0。
为什么 cookie 身份验证 (HttpContext.SignInAsync()
/ HttpContext.AuthenticateAsync()
) 会失败?
答案 0 :(得分:7)
这是自 Asp.Net Core 3.0 Preview 6 以来的重大变更。文档位于 https://docs.microsoft.com/en-us/dotnet/core/compatibility/aspnetcore#identity-signinasync-throws-exception-for-unauthenticated-identity,但不包含重大变更的动机。
真正的动机在这里: https://github.com/dotnet/aspnetcore/issues/9255
简而言之,您需要明确指定身份验证方案:
new ClaimsIdentity(claims, /*Explicit*/CookieAuthenticationDefaults.AuthenticationScheme)
我遇到了同样的问题,这个变化对我有帮助。
答案 1 :(得分:1)
只是为了建立在 Dmitriy 的回答之上,这里是一个有效登录的片段(.NET 5.0,可能适用于 3.0 及更高版本):
var claims = new List<Claim>
{
// example claims from external API
new Claim("sub", userId),
new Claim(ClaimTypes.Name, username)
};
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
var signIn = HttpContext.SignInAsync(new ClaimsPrincipal(claimsIdentity),
_userService.AuthenticationOptions(model.RememberMe));