我对一个ASP.NET核心2.1站点有一个奇怪的问题。当我登录到它并在30分钟后刷新它时,总是会引发以下异常:
InvalidOperationException:没有为方案“Identity.External”注册注销身份验证处理程序。已注册的注销方案为:identity.application。是否忘记调用addauthentication().addcookies(“identity.external”,…)?
没错,我没有
Identity.External
注册了,但我也不想注册。为什么它一直试图注销它?以下是我注册cookie的方法:
services.AddAuthentication(
o => {
o.DefaultScheme = IdentityConstants.ApplicationScheme;
}).AddCookie(IdentityConstants.ApplicationScheme,
o => {
o.Events = new CookieAuthenticationEvents {
OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
};
});
services.ConfigureApplicationCookie(
o => {
o.Cookie.Expiration = TimeSpan.FromHours(2);
o.Cookie.HttpOnly = true;
o.Cookie.SameSite = SameSiteMode.Strict;
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
o.AccessDeniedPath = "/admin";
o.LoginPath = "/admin";
o.LogoutPath = "/admin/sign-out";
o.SlidingExpiration = true;
});
有人能给我指出解决这个问题的正确方向吗?
更新
这是@edward在评论中要求的完整代码和使用过程。为了简洁,我省略了一些部分。
Startup.cs
public sealed class Startup {
public void ConfigureServices(
IServiceCollection services) {
// ...
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddApplicationIdentity();
services.AddScoped<ApplicationSignInManager>();
services.Configure<IdentityOptions>(
o => {
o.Password.RequiredLength = 8;
o.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
o.Lockout.MaxFailedAccessAttempts = 5;
});
services.ConfigureApplicationCookie(
o => {
o.Cookie.Name = IdentityConstants.ApplicationScheme;
o.Cookie.Expiration = TimeSpan.FromHours(2);
o.Cookie.HttpOnly = true;
o.Cookie.SameSite = SameSiteMode.Strict;
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
o.AccessDeniedPath = "/admin";
o.LoginPath = "/admin";
o.LogoutPath = "/admin/sign-out";
o.SlidingExpiration = true;
});
// ...
}
public void Configure(
IApplicationBuilder app) {
// ...
app.UseAuthentication();
// ...
}
}
ServiceCollectionExtensions.cs
public static class ServiceCollectionExtensions {
public static IdentityBuilder AddApplicationIdentity(
this IServiceCollection services) {
services.AddAuthentication(
o => {
o.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
o.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
o.DefaultForbidScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignInScheme = IdentityConstants.ApplicationScheme;
o.DefaultSignOutScheme = IdentityConstants.ApplicationScheme;
}).AddCookie(IdentityConstants.ApplicationScheme,
o => {
o.Events = new CookieAuthenticationEvents {
OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync
};
});
services.TryAddScoped<SignInManager<User>, ApplicationSignInManager>();
services.TryAddScoped<IPasswordHasher<User>, PasswordHasher<User>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<User>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<User>, UserClaimsPrincipalFactory<User>>();
services.TryAddScoped<UserManager<User>>();
services.TryAddScoped<IUserStore<User>, ApplicationUserStore>();
return new IdentityBuilder(typeof(User), services);
}
}
DefaultController.cs
[Area("Admin")]
public sealed class DefaultController :
AdminControllerBase {
[HttpPost, AllowAnonymous]
public async Task<IActionResult> SignIn(
SignIn.Command command) {
var result = await Mediator.Send(command);
if (result.Succeeded) {
return RedirectToAction("Dashboard", new {
area = "Admin"
});
}
return RedirectToAction("SignIn", new {
area = "Admin"
});
}
[HttpGet, ActionName("sign-out")]
public async Task<IActionResult> SignOut() {
await Mediator.Send(new SignOut.Command());
return RedirectToAction("SignIn", new {
area = "Admin"
});
}
}
SignIn.cs
public sealed class SignIn {
public sealed class Command :
IRequest<SignInResult> {
public string Password { get; set; }
public string Username { get; set; }
}
public sealed class CommandHandler :
HandlerBase<Command, SignInResult> {
private ApplicationSignInManager SignInManager { get; }
public CommandHandler(
DbContext context,
ApplicationSignInManager signInManager)
: base(context) {
SignInManager = signInManager;
}
protected override SignInResult Handle(
Command command) {
var result = SignInManager.PasswordSignInAsync(command.Username, command.Password, true, false).Result;
return result;
}
}
}
SignOut.cs
public sealed class SignOut {
public sealed class Command :
IRequest {
}
public sealed class CommandHandler :
HandlerBase<Command> {
private ApplicationSignInManager SignInManager { get; }
public CommandHandler(
DbContext context,
ApplicationSignInManager signInManager)
: base(context) {
SignInManager = signInManager;
}
protected override async void Handle(
Command command) {
await SignInManager.SignOutAsync();
}
}
}
有所有相关的代码,从我如何配置身份到我如何登录和注销。我仍然不知为什么
身份。外部
当我从未要求它的时候,它就出现了。
技术上来说
SignIn
和
SignOut
可以删除类,并将其功能合并到
DefaultController
但是,我选择保持它们以保持应用程序结构的一致性。