一旦已使用.Net核心身份电子邮件确认令牌,该令牌应无效

时间:2020-07-17 11:58:32

标签: c# .net-core identityserver4 asp.net-core-3.1 .net-core-3.1

我正在使用GenerateEmailConfirmationTokenAsync生成令牌电子邮件确认链接,并使用ConfirmEmailAsync来验证链接。一切正常。

问题-链接只能运行一次。如果用户使用相同的链接,则第二次链接应该无效。我每次ConfirmEmailAsync IdentityResult.IsSucceded true时都进行调试和发现。我曾期望VerifyUserTokenAsync第二次返回false,但始终返回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);
});

1 个答案:

答案 0 :(得分:3)

我认为您需要将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;

}

可以与密码重置类似。

方法2,尚未尝试,但请尝试一下, 确认完成后,尝试修改令牌的安全时间戳,以使令牌无效

UserManager.UpdateSecurityStampAsync(userId);