我正在使用Asp.Net Identity生成密码重置令牌。
string Token = userManager.GeneratePasswordResetToken(userId);
上面的代码给了我一个很长的令牌。 是否可以生成短长度的密码重置令牌?
答案 0 :(得分:1)
您可以使用TotpSecurityStampBasedTokenProvider
生成6位数字:
public class ResetPasswordTokenProvider : TotpSecurityStampBasedTokenProvider<OriIdentityUser>
{
public const string ProviderKey = "ResetPassword";
public override Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<OriIdentityUser> manager, OriIdentityUser user)
{
return Task.FromResult(false);
}
}
然后在启动类中添加:
services.AddIdentity<IdentityUser, IdentityRole>(options =>
{
options.Tokens.PasswordResetTokenProvider = ResetPasswordTokenProvider.ProviderKey;
})
.AddDefaultTokenProviders()
.AddTokenProvider<ResetPasswordTokenProvider>(ResetPasswordTokenProvider.ProviderKey);
答案 1 :(得分:0)
您的密码重置令牌需要以加密方式随机 - 这意味着给定一组使用过的令牌,下一个令牌应该是无法猜测的。它还需要涵盖一组足够大的可能值,这些值可能会使得所有这些值的实力变得非常缓慢。
您可以进行更改以使后者使用较小的可能值集合 - 例如,您可以在检查令牌之前向密码重置页面/操作添加1秒延迟。您的用户几乎不会注意到很少使用的页面上的延迟,但攻击者将无法快速尝试大量令牌。
因此,首先您需要获取加密随机数:
var random = new byte[8];
using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create())
rng.GetBytes(random);
我在这里放了8
字节,但你可以根据需要设置这个字节。
接下来,您需要将其转换为一个漂亮的可复制粘贴字符串。你可以通过unicode转换实现这一点,但我发现base 64更可靠:
Convert.ToBase64String(random).TrimEnd('=');
将此项与8
字节一起使用将为您提供64位可能的值和10个字符串。使用4
将为您提供32位(可能足以在低安全性站点上进行慢速令牌检查)和5个字符串。
答案 2 :(得分:0)
将较长的代码替换为较短的代码,然后存储在应用程序缓存中。
生成时:
var token = UserManager.GeneratePasswordResetToken(user.Id);
var guidCode = GenerateCustomToken(); //use this https://stackoverflow.com/a/1668371/631527
CacheHelper.AddToCache(guid, token); //add it to MemoryCache.Default
var resetUrl = $"https://.....com/password-reset/{guidCode}/{userName}";
检查时:
//get guidCode from the request in your GET or POST controller
var token = CacheHelper.GetValue(guidCode); //retrieve it from cache
var result = UserManager.ResetPassword(user.Id, token, model.Password);
答案 3 :(得分:0)
一件事是生成自己的8位GUID并将其发送给用户,并拥有自己的查询表以获取真实令牌。
答案 4 :(得分:0)
我有一个理想的解决方案,它建立在此处找到的体面答案的基础上。首先,您必须在相关类中注入 IMemoryCache
。
public class ResetController : ControllerBase
{
private readonly IMemoryCache _memoryCache;
public ResetController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
}
其次,内存缓存允许您创建存储在缓存中的键值对关系,以便您稍后可以使用键检索值。在这种情况下,值是实际生成的令牌,键是变量 truncatedtoken
。
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
string tokentruncated;
using (RandomNumberGenerator rng = new RNGCryptoServiceProvider())
{
byte[] tokenData = new byte[32];
rng.GetBytes(tokenData);
tokentruncated = Convert.ToBase64String(tokenData);
}
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromDays(1));
_memoryCache.Set(tokentrunc, token, cacheEntryOptions);
发送确认令牌 (truncatedtoken
) 并且用户准备好重置密码后。 truncatedtoken
键用于检索实际令牌。
string token;
_memoryCache.TryGetValue(truncatedtoken, out token);
var result = await _userManager.ResetPasswordAsync(user, token, "New password");
除了使用 TryGetValue
,您还可以使用;
string token = _memoryCache.Get<string>(truncatedtoken);