代码之家  ›  专栏  ›  技术社区  ›  Gup3rSuR4c

“identity.external”的ASP.NET核心标识异常

  •  5
  • Gup3rSuR4c  · 技术社区  · 6 年前

    我对一个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 但是,我选择保持它们以保持应用程序结构的一致性。

    2 回复  |  直到 5 年前
        1
  •  2
  •   Shche    5 年前

    here

    services.AddIdentityCore<ApplicationUser>()
                    .AddUserStore<UserStore>()
                    .AddDefaultTokenProviders()
                    .AddSignInManager<SignInManager<ApplicationUser>>();
    

    then Identity would try to close the session of the Application Scheme, the Extern one and also the TwoFactor

    public virtual async Task SignOutAsync()
    {
        await Context.SignOutAsync(IdentityConstants.ApplicationScheme);
        await Context.SignOutAsync(IdentityConstants.ExternalScheme); //<- Problem and...
        await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme); //... another problem.
    }
    

    Adding the cookies for every scheme

    public class SignInManager<TUser> : Microsoft.AspNetCore.Identity.SignInManager<TUser> 
        where TUser : class
    {
        public SignInManager(
            UserManager<TUser> userManager, 
            IHttpContextAccessor contextAccessor, 
            IUserClaimsPrincipalFactory<TUser> claimsFactory, 
            IOptions<IdentityOptions> optionsAccessor, 
            ILogger<Microsoft.AspNetCore.Identity.SignInManager<TUser>> logger, 
            IAuthenticationSchemeProvider schemes) 
            : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes)
        {
        }
    
        public async override Task SignOutAsync()
        {
            await Context.SignOutAsync(IdentityConstants.ApplicationScheme); // <- 
        }
    }
    

    services.AddIdentityCore<ApplicationUser>()
                    .AddUserStore<UserStore>()
                    .AddDefaultTokenProviders()
                    .AddSignInManager<Services.Infrastructure.Identity.SignInManager<ApplicationUser>>() //<-
    
        2
  •  0
  •   Gup3rSuR4c    5 年前

    public static class IdentityExtensions {
        public static IServiceCollection AddApplicationIdentity(
            this IServiceCollection services) {
            services.AddAuthentication(
                o => {
                    o.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
                    o.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
                    o.DefaultSignInScheme = IdentityConstants.ApplicationScheme;
                }).AddCookie(IdentityConstants.ApplicationScheme,
                o => {
                    o.Cookie.Expiration = TimeSpan.FromHours(8);
                    o.Cookie.SameSite = SameSiteMode.Strict;
                    o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    
                    o.AccessDeniedPath = new PathString("/");
                    o.ExpireTimeSpan = TimeSpan.FromHours(8);
                    o.LoginPath = new PathString("/sign-in");
                    o.LogoutPath = new PathString("/sign-out");
                    o.SlidingExpiration = true;
                });
    
            services.AddIdentityCore<User>(
                        o => {
                            o.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
                            o.Lockout.MaxFailedAccessAttempts = 5;
    
                            o.Password.RequiredLength = 8;
                        })
                    .AddSignInManager<ApplicationSignInManager>()
                    .AddUserStore<ApplicationUserStore>();
    
            services.Configure<SecurityStampValidatorOptions>(
                o => {
                    o.ValidationInterval = TimeSpan.FromMinutes(1);
                });
    
            return services;
        }
    }