Identity Framework测试确认电子邮件令牌是否已过期

Car*_*rel 18 asp.net asp.net-mvc email-confirmation asp.net-identity

是否可以使用Identity Framework测试确认电子邮件令牌是否已过期UserManager?无论错误是什么,请从以下内容:

var result = await UserManager.ConfirmEmailAsync(userId, code);
Run Code Online (Sandbox Code Playgroud)

我得到一个通用的"无效令牌"错误.

Pat*_*Pat 7

我找到了一种方法来解析发布日期的令牌,然后您可以检查是否在允许的时间范围内(如果未指定则默认为24小时).

Identity.cs

ApplicationUserManager

public IDataProtector Protector { get; set; }

public TimeSpan TokenLifespan { get; set; }
Run Code Online (Sandbox Code Playgroud)

ApplicationUserManager Create()

// Explicitly set token expiration to 24 hours. 
manager.TokenLifespan = TimeSpan.FromHours(24);
var dataProtectionProvider = options.DataProtectionProvider;
manager.Protector = dataProtectionProvider.Create("ASP.NET Identity");

if (dataProtectionProvider != null)
{
    manager.UserTokenProvider =
        new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"))
        {
            TokenLifespan = manager.TokenLifespan
        };
}
Run Code Online (Sandbox Code Playgroud)

AccountController.cs

public async Task<ActionResult> ConfirmEmail(string Code, string UserId)
{
// Try/catch, validation, etc.
var tokenExpired = false;
var unprotectedData = UserManager.Protector.Unprotect(Convert.FromBase64String(Code));
var ms = new MemoryStream(unprotectedData);
using (BinaryReader reader = new BinaryReader(ms))
{
    var creationTime = new DateTimeOffset(reader.ReadInt64(), TimeSpan.Zero);
    var expirationTime = creationTime + UserManager.TokenLifespan;
    if (expirationTime < DateTimeOffset.UtcNow)
    {
        tokenExpired = true;
    }
 }
 // Do something if token is expired, else continue with confirmation
}
Run Code Online (Sandbox Code Playgroud)

我发现这个博客帖子和恩科西的答案是非常有帮助的,如果你想通过身份源代码,微软就在这里(为MVC5和较低的身份以前版本在这里).另外,如果它的形式很差,我很抱歉回答你自己提出的问题,但我忍不住继续寻找更好的解决方案.

  • 提供帮助其他人是否赏金的答案就是这个网站的意义所在.我觉得这个答案很有意思,并会进一步调查,以确保没有任何缺陷.它具有我迄今为止看到的潜力. (2认同)

Nko*_*osi 6

我通过保留/存储生成的令牌的副本来解决这个问题

public class ApplicationUser : IdentityUser {
    public string EmailConfirmationToken { get; set; }
    public string ResetPasswordToken { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

并将其与派生中的用户相关联UserManager<ApplicationUser>.

public override async System.Threading.Tasks.Task<string> GenerateEmailConfirmationTokenAsync(string userId) {
    /* NOTE:
        * The default UserTokenProvider generates tokens based on the users's SecurityStamp, so until that changes
        * (like when the user's password changes), the tokens will always be the same, and remain valid. 
        * So if you want to simply invalidate old tokens, just call manager.UpdateSecurityStampAsync().
        */
    //await base.UpdateSecurityStampAsync(userId);

    var token = await base.GenerateEmailConfirmationTokenAsync(userId);
    if (!string.IsNullOrEmpty(token)) {
        var user = await FindByIdAsync(userId);
        user.EmailConfirmationToken = token; //<<< Last issued token
        //Note: If a token is generated then the current email is no longer confirmed.
        user.EmailConfirmed = false;
        await UpdateAsync(user);
    }
    return token;
}
Run Code Online (Sandbox Code Playgroud)

当提供令牌以进行确认时,通过令牌搜索用户.

public static class ApplicationUserManagerExtension {
    public static Task<string> FindIdByEmailConfirmationTokenAsync(this UserManager<ApplicationUser> manager, string confirmationToken) {
        string result = null;
        ApplicationUser user = manager.Users.SingleOrDefault(u => u.EmailConfirmationToken != null && u.EmailConfirmationToken == confirmationToken);
        if (user != null) {
            result = user.Id;
        }
        return Task.FromResult(result);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果令牌与已知用户匹配,表明它是有效颁发的令牌.

然后将尝试使用用户管理器确认令牌.

如果确认失败,则令牌已过期并采取适当的操作.

否则,如果令牌确认,则将其从关联用户移除,从而使该令牌的重用无效.

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;
}
Run Code Online (Sandbox Code Playgroud)

密码重置也采用了类似的方法.