.NET 6使用SignInManager登录报错:未注册认证处理程序
问题:.NET 6用户认证中出现"No sign-in authentication handlers are registered"错误
运行代码时遇到以下错误:
System.InvalidOperationException: No sign-in authentication handlers are registered. Did you forget to call AddAuthentication().AddCookie("Identity.Application",...)? at Microsoft.AspNetCore.Authentication.AuthenticationService.SignInAsync(HttpContext context, String scheme, ClaimsPrincipal principal, AuthenticationProperties properties) at Microsoft.AspNetCore.Identity.SignInManager`1.SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable`1 additionalClaims) at Microsoft.AspNetCore.Identity.SignInManager`1.SignInOrTwoFactorAsync(TUser user, Boolean isPersistent, String loginProvider, Boolean bypassTwoFactor) at Microsoft.AspNetCore.Identity.SignInManager`1.PasswordSignInAsync(TUser user, String password, Boolean isPersistent, Boolean lockoutOnFailure) at Microsoft.AspNetCore.Identity.SignInManager`1.PasswordSignInAsync(String userName, String password, Boolean isPersistent, Boolean lockoutOnFailure) at ApplicationCore.Infrastructure.Services.IdentityService.SigninUserAsync(String userName, String password) in C:\Users\Radhoine\source\repos\ApplicationCore\ApplicationCore.Infrastructure\Services\IdentityService.cs:line 218 at ApplicationCore.Application.Commands.Auth.AuthCommandHandler.Handle(AuthCommand request, CancellationToken cancellationToken) in C:\Users\Radhoine\source\repos\ApplicationCore\ApplicationCore.Application\Commands\Auth\AuthCommand.cs:line 32 at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) at ApplicationCore.API.Controllers.AuthController.Login(AuthCommand command) in C:\Users\Radhoine\source\repos\ApplicationCore\ApplicationCore.API\Controllers\AuthController.cs:line 23 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
相关代码
program.cs中的配置
program.cs中的配置
var _key = builder.Configuration["Jwt:Key"]; var _issuer = builder.Configuration["Jwt:Issuer"]; var _audience = builder.Configuration["Jwt:Audience"]; var _expirtyMinutes = builder.Configuration["Jwt:ExpiryMinutes"]; // Configuration for token builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; }).AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters() { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidAudience = _audience, ValidIssuer = _issuer, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_key)), ClockSkew = TimeSpan.FromMinutes(Convert.ToDouble(_expirtyMinutes)) }; }); // Dependency injection with key builder.Services.AddSingleton<ITokenGenerator>(new TokenGenerator(_key, _issuer, _audience, _expirtyMinutes)); // Include Infrastructur Dependency builder.Services.AddInfrastructure(builder.Configuration);
IdentityService类代码
IdentityService类代码
public class IdentityService : IIdentityService { private readonly UserManager<PartenaireContact> _userManager; private readonly SignInManager<PartenaireContact> _signInManager; private readonly RoleManager<IdentityRole> _roleManager; public IdentityService(UserManager<PartenaireContact> userManager, SignInManager<PartenaireContact> signInManager, RoleManager<IdentityRole> roleManager) { _userManager = userManager; _signInManager = signInManager; _roleManager = roleManager; _roleManager = roleManager; } public async Task<bool> SigninUserAsync(string userName, string password) { var result = await _signInManager.PasswordSignInAsync(userName, password, true, false); return result.Succeeded; } }
问题原因与解决方法
原因分析
SignInManager.PasswordSignInAsync方法默认依赖Cookie认证处理程序来创建用户会话,但你当前只配置了JWT认证,没有注册任何用于登录的Cookie认证处理器,所以抛出该错误。
两种解决思路
思路1:添加Cookie认证配置(适用于需要Cookie会话的场景)
如果你的系统需要同时支持Cookie会话和JWT认证,或者依赖SignInManager的会话管理能力,需要在AddAuthentication中添加Cookie认证配置:
// 引用命名空间 using Microsoft.AspNetCore.Authentication.Cookies; builder.Services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; // 指定登录用的Scheme }) .AddJwtBearer(x => { // 原JWT配置保持不变 }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { // 可根据需求配置Cookie属性 options.ExpireTimeSpan = TimeSpan.FromMinutes(30); options.Cookie.Name = "YourAppAuthCookie"; options.LoginPath = "/auth/login"; // 未登录时的跳转路径(如果需要) });
思路2:改用纯JWT认证流程(推荐,适用于无会话的API场景)
如果你的系统是纯API架构,不需要服务端保存用户会话,应该直接验证密码并生成JWT令牌,而不是使用SignInManager.PasswordSignInAsync(该方法是为Cookie登录设计的)。
修改IdentityService的SigninUserAsync方法:
public async Task<string> SigninUserAsync(string userName, string password) { // 查找用户 var user = await _userManager.FindByNameAsync(userName); if (user == null || !await _userManager.CheckPasswordAsync(user, password)) { return null; // 验证失败返回null } // 收集用户声明(如角色、ID等) var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, user.Id), new Claim(ClaimTypes.Name, user.UserName) }; var roles = await _userManager.GetRolesAsync(user); claims.AddRange(roles.Select(r => new Claim(ClaimTypes.Role, r))); // 调用你的TokenGenerator生成JWT令牌 return _tokenGenerator.GenerateToken(claims); }
注意:需要在IdentityService的构造函数中注入ITokenGenerator:
private readonly ITokenGenerator _tokenGenerator; public IdentityService(UserManager<PartenaireContact> userManager, SignInManager<PartenaireContact> signInManager, RoleManager<IdentityRole> roleManager, ITokenGenerator tokenGenerator) { _userManager = userManager; _signInManager = signInManager; _roleManager = roleManager; _tokenGenerator = tokenGenerator; }
这样修改后,登录接口验证用户密码后直接返回JWT令牌,客户端后续请求携带令牌即可完成认证,符合纯API的JWT认证模式。
内容的提问来源于stack exchange,提问作者Rad
相关产品推荐
相关产品推荐

