.Net Core 身份电子邮件确认令牌一旦使用就应该无效
.Net Core Identtiy Email Confirm Token should be invalid once already used
我正在使用 GenerateEmailConfirmationTokenAsync to generate the token Email Confirmation Link and using ConfirmEmailAsync 来验证 link。它工作正常。
问题 - Link 应该只能工作一次。如果用户第二次使用相同的 link link 应该是无效的。我调试并发现每次 ConfirmEmailAsync IdentityResult.IsSucceded true. I was expecting VerifyUserTokenAsync 第二次应该 return false 但它总是 returning true.
请提出解决方案。谢谢
使用 .Net Core 3.1,Identity Server 4
// To Generate Token
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
// To Confirm Token
var result = await _userManager.ConfirmEmailAsync(user, code);
// Customised Token Provider
public class EmailConfirmationTokenProvider<TUser> : DataProtectorTokenProvider<TUser> where TUser : class
{
public EmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
IOptions<EmailConfirmationTokenProviderOptions> options, ILogger<EmailConfirmationTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{ }
// Starup.cs Code
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Tokens.EmailConfirmationTokenProvider = "email_confirmation_provider";
options.SignIn.RequireConfirmedEmail = true;
})
.AddDefaultTokenProviders()
.AddTokenProvider<EmailConfirmationTokenProvider<ApplicationUser>>("email_confirmation_provider");
services.Configure<EmailConfirmationTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromSeconds(3600);
});
我认为您需要将 ConfirmEmailAsync
的行为改写成这样,
如果令牌与已知用户匹配,则表明它是有效颁发的令牌。
然后将尝试与用户管理器确认令牌。
如果确认失败,则令牌已过期并采取适当的措施。
否则,如果令牌已确认,则会将其从关联用户中删除,从而使该令牌的重用无效。
public override async System.Threading.Tasks.Task<IdentityResult> ConfirmEmailAsync(string userId, string token) {
var user = await FindByIdAsync(userId);
if (user == null) {
return IdentityResult.Failed("User Id Not Found");
}
var result = await base.ConfirmEmailAsync(userId, token);
if (result.Succeeded) {
user.EmailConfirmationToken = null;
return await UpdateAsync(user);
} else if (user.EmailConfirmationToken == token) {
//Previously Issued Token expired
result = IdentityResult.Failed("Expired Token");
}
return result;
}
密码重置也可以执行类似的操作。
方法二,还没试过试一试,
尝试修改令牌的安全时间戳以在确认完成后使它们失效,
UserManager.UpdateSecurityStampAsync(userId);
我正在使用 GenerateEmailConfirmationTokenAsync to generate the token Email Confirmation Link and using ConfirmEmailAsync 来验证 link。它工作正常。
问题 - Link 应该只能工作一次。如果用户第二次使用相同的 link link 应该是无效的。我调试并发现每次 ConfirmEmailAsync IdentityResult.IsSucceded true. I was expecting VerifyUserTokenAsync 第二次应该 return false 但它总是 returning true.
请提出解决方案。谢谢
使用 .Net Core 3.1,Identity Server 4
// To Generate Token
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
// To Confirm Token
var result = await _userManager.ConfirmEmailAsync(user, code);
// Customised Token Provider
public class EmailConfirmationTokenProvider<TUser> : DataProtectorTokenProvider<TUser> where TUser : class
{
public EmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
IOptions<EmailConfirmationTokenProviderOptions> options, ILogger<EmailConfirmationTokenProvider<TUser>> logger)
: base(dataProtectionProvider, options, logger)
{
}
}
public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{ }
// Starup.cs Code
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.Tokens.EmailConfirmationTokenProvider = "email_confirmation_provider";
options.SignIn.RequireConfirmedEmail = true;
})
.AddDefaultTokenProviders()
.AddTokenProvider<EmailConfirmationTokenProvider<ApplicationUser>>("email_confirmation_provider");
services.Configure<EmailConfirmationTokenProviderOptions>(options =>
{
options.TokenLifespan = TimeSpan.FromSeconds(3600);
});
我认为您需要将 ConfirmEmailAsync
的行为改写成这样,
如果令牌与已知用户匹配,则表明它是有效颁发的令牌。 然后将尝试与用户管理器确认令牌。 如果确认失败,则令牌已过期并采取适当的措施。
否则,如果令牌已确认,则会将其从关联用户中删除,从而使该令牌的重用无效。
public override async System.Threading.Tasks.Task<IdentityResult> ConfirmEmailAsync(string userId, string token) {
var user = await FindByIdAsync(userId);
if (user == null) {
return IdentityResult.Failed("User Id Not Found");
}
var result = await base.ConfirmEmailAsync(userId, token);
if (result.Succeeded) {
user.EmailConfirmationToken = null;
return await UpdateAsync(user);
} else if (user.EmailConfirmationToken == token) {
//Previously Issued Token expired
result = IdentityResult.Failed("Expired Token");
}
return result;
}
密码重置也可以执行类似的操作。
方法二,还没试过试一试, 尝试修改令牌的安全时间戳以在确认完成后使它们失效,
UserManager.UpdateSecurityStampAsync(userId);