Stack Overflow Asked on November 20, 2021
I am using GenerateEmailConfirmationTokenAsync to generate the token Email Confirmation Link and using ConfirmEmailAsync to Validate the link. It is working fine.
Problem – Link should work only once. If user using same link 2nd time link should be invalid. I debug and found each time ConfirmEmailAsync IdentityResult.IsSucceded true. I was expecting VerifyUserTokenAsync should return false second time but it is always returning true.
Please suggest solution. Thanks
Using .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);
});
I think you need to override the behavior of ConfirmEmailAsync
to something like this,
If the token matches a known user that indicates that it was a validly issued token. Will then attempt to confirm token with User manager. If confirmation fails then token has expired and an appropriate action is taken.
Else if the token confirmed, it is removed from associated user and thus invalidating the reuse of that token.
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;
}
Similar can be done for password resets.
Approach 2, not tried yet but give a try, Try to modify the Security timestamps of token to invalidate those once confirmation is done,
UserManager.UpdateSecurityStampAsync(userId);
Answered by Sohan on November 20, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP