.Net Core 重置密码令牌和 Identityserver 4 令牌无效

use*_*196 5 c# asp.net-identity asp.net-core identityserver4

我的应用程序和 API 使用 IdentityServer 4 进行保护。

我有一个用于用户管理的集中 API(注册新用户、更新、删除和重置密码)。这个 api 生成的令牌将被 identityserver 用来重置用户的密码。

问题是我总是收到无效令牌错误。我知道这与 url 编码无关,因为忘记的密码由身份服务器处理,并且身份服务器生成的令牌工作正常。问题是当令牌由不同的 api 生成时(即使在一台机器上)。

我考虑创建一个通用的数据保护提供程序,但我不清楚这是如何完成的。基本上,我怎样才能重置由另一个接受的一个 api 创建的密码令牌?

我正在使用 Asp Identity 的用户管理器来生成重置密码令牌:

var token = await _userManager.GeneratePasswordResetTokenAsync(appUser);
Run Code Online (Sandbox Code Playgroud)

这是我的 IdentityServer 被设置为使用 Asp Identity 的方式:

services
    .AddIdentity<ApplicationUser, IdentityRole>(options =>
        {
            options.Lockout.AllowedForNewUsers = true;
            options.Lockout.DefaultLockoutTimeSpan = new System.TimeSpan(12, 0, 0);
            options.Lockout.MaxFailedAccessAttempts = int.Parse(Configuration["MaxFailedAttempts"]);
        })
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

...

var builder = services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
                options.Authentication.CookieSlidingExpiration = true;
            })
            .AddAspNetIdentity<ApplicationUser>()
            .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = b =>
                    b.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));

                    options.DefaultSchema = Globals.SCHEMA_IDS;
                })
            // this adds the operational data from DB (codes, tokens, consents)
            .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = b =>
                    b.UseSqlServer(connectionString,
                    sql => sql.MigrationsAssembly(migrationsAssembly));

                    options.DefaultSchema = Globals.SCHEMA_IDS;
                    // this enables automatic token cleanup. this is optional.
                    options.EnableTokenCleanup = true;
                    options.TokenCleanupInterval = 30;
                })
            .AddProfileService<CustomProfileService>()
            .AddSigninCredentialFromConfig(Configuration.GetSection("SigninKeyCredentials"), Logger);
Run Code Online (Sandbox Code Playgroud)

这就是我的 UserManagement Api 设置为使用 Asp Identity 的方式:

services.AddTransient<IUserStore<ApplicationUser>, UserStore<ApplicationUser, IdentityRole, ApplicationDbContext>>();
services.AddTransient<IRoleStore<IdentityRole>, RoleStore<IdentityRole, ApplicationDbContext>>();
services.AddTransient<IPasswordHasher<ApplicationUser>, PasswordHasher<ApplicationUser>>();
services.AddTransient<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.AddTransient<IdentityErrorDescriber>();

var identityBuilder = new IdentityBuilder(typeof(ApplicationUser), typeof(IdentityRole), services);
identityBuilder.AddTokenProvider("Default", typeof(DataProtectorTokenProvider<ApplicationUser>));
services.AddTransient<UserManager<ApplicationUser>>();
Run Code Online (Sandbox Code Playgroud)

use*_*196 5

必须继续讨论其他问题,现在才回到这个问题。我最终通过确保所有 API 和 IdentityServer 实例都配置为使用 ASP.NET Core 数据保护来解决这个问题。我使用 Redis 作为我的分布式缓存系统,因此只需配置我的每个 api 和身份服务器,并且现在在生成令牌时所有内容都使用相同的密钥。以下是我在每个startup.cs中使用的内容:

public void ConfigureServices(IServiceCollection services)
{
  ...            
            services.AddSession();
            services.Configure<RedisConfiguration>(Configuration.GetSection("redis"));
            services.AddDistributedRedisCache(options =>
            {
                options.Configuration = Configuration.GetValue<string>("redis:host");
            });
            var redis = ConnectionMultiplexer.Connect(Configuration.GetValue<string>("redis:host"));
            services.AddDataProtection()
                .PersistKeysToRedis(redis, "DataProtection-Keys")
                .SetApplicationName(<application name>);
            services.AddTransient<ICacheService, CacheService>();
...
}
Run Code Online (Sandbox Code Playgroud)

然后不要忘记使用会话(在 API 中):

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            ...
            app.UseAuthentication();
            app.UseSession();
            ...
        }
Run Code Online (Sandbox Code Playgroud)

使用会话(在 IdentityServer 中):

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            ...
            app.UseIdentityServer();
            app.UseSession();
            ...
        }
Run Code Online (Sandbox Code Playgroud)