我的应用程序和API使用IdentityServer 4保护。
我有一个用于用户管理的集中API(注册新用户,更新,删除和重置密码)。此api生成的令牌将被Identityserver用来重置用户密码。
问题是我总是收到无效的令牌错误。我知道这与url编码无关,因为忘记的密码由身份服务器处理,并且身份服务器生成的令牌工作正常。问题在于令牌是由不同的api(甚至在一台机器上)生成的。
我曾考虑创建一个通用的数据保护提供程序,但不清楚如何实现。 基本上,如何重置一个由另一个api接受的api创建的密码令牌?
我正在使用Asp Identity的用户管理器来生成重置密码令牌:
var token = await _userManager.GeneratePasswordResetTokenAsync(appUser);
这是我的IdentityServer设置为使用Asp身份的方式:
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);
这是我的UserManagement Api设置为使用Asp身份的方式:
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>>();
答案 0 :(得分:0)
由于这是一个2个月大的问题,我想您已经解决了。我的建议是:看一下令牌的使用寿命。像这样在您的startup.cs中设置它:
services.Configure<DataProtectionTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromHours(tokenlifespan);
});
希望这对您有帮助!
答案 1 :(得分:0)
不得不继续讨论其他问题,而现在又回到了这一点。最后,通过确保所有API和IdentityServer实例都配置为使用ASP.NET Core数据保护来解决此问题。我使用redis作为我的分布式缓存系统,因此只需要配置我的api和identityserver,现在生成令牌时所有东西都使用相同的密钥。以下是我在每个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>();
...
}
,然后别忘了使用会话(在API中):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseAuthentication();
app.UseSession();
...
}
使用会话(在IdentityServer中):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseIdentityServer();
app.UseSession();
...
}