AspnetIdentity在哪里存储UserTokens?
我有ASP.Net MVC5应用程序。在创建应用程序时,您选择个人认证Visual Studio使用脚手架,并添加代码登录,创建用户,忘记密码等我使用这个默认实现ForgotPassword功能。这是忘记密码的工作原理。AspnetIdentity在哪里存储UserTokens?
1>用户点击忘记密码链接。
2>用户输入他的电子邮件地址。
3>应用程序创建新的令牌并在查询字符串中发送带有带有令牌的返回URL的电子邮件。
4>用户单击电子邮件中的链接并重定向到ResetPassword页面。
5>用户输入新密码并点击提交。
6>应用程序验证用户和令牌并重置密码。
问题。
1>收到电子邮件后用户不能立即点击链接,他可能会在某个时间之后,甚至在几天后点击。在ASP.NET应用程序存储令牌的位置之间?我没有在数据库中看到它。
2>令牌上是否有任何过期。
3>在忘记密码屏幕上,用户输入他的电子邮件并单击提交以接收带有令牌的电子邮件。假设他这样做了3次。所以他会收到3封邮件和3个不同的标记。然后他点击任何一封电子邮件中的链接并重置密码。其他2封电子邮件中未使用的令牌会发生什么变化,它们仍然有效吗?用户是否可以点击其他电子邮件中的链接并可以重置密码?
基本上,如果你看看由ASP.Net Identity创建的用户,你会看到一列SecurityStamp
,它基本上是散列,用于所有与密码相关的场景。实际上,当用户更改密码时,它会发生更改。
当您单击与该用户关联的重置密码SecurityStamp
用于生成通过电子邮件发送的令牌时。看到在这里GenerateAsync
方法的源代码(有2个供应商)
public virtual async Task<string> GenerateAsync(string purpose, UserManager<TUser> manager, TUser user)
{
if (manager == null)
{
throw new ArgumentNullException(nameof(manager));
}
var token = await manager.CreateSecurityTokenAsync(user);
var modifier = await GetUserModifierAsync(purpose, manager, user);
return Rfc6238AuthenticationService.GenerateCode(token, modifier).ToString("D6", CultureInfo.InvariantCulture);
}
或
public virtual async Task<string> GenerateAsync(string purpose, UserManager<TUser> manager, TUser user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user));
}
var ms = new MemoryStream();
var userId = await manager.GetUserIdAsync(user);
using (var writer = ms.CreateWriter())
{
writer.Write(DateTimeOffset.UtcNow);
writer.Write(userId);
writer.Write(purpose ?? "");
string stamp = null;
if (manager.SupportsUserSecurityStamp)
{
stamp = await manager.GetSecurityStampAsync(user);
}
writer.Write(stamp ?? "");
}
var protectedBytes = Protector.Protect(ms.ToArray());
return Convert.ToBase64String(protectedBytes);
}
一旦用户点击该链接,并提交新的密码在电子邮件中发送的令牌也会被提交并且针对SecurityStamp进行验证。
public virtual async Task<bool> ValidateAsync(string purpose, string token, UserManager<TUser> manager, TUser user)
{
if (manager == null)
{
throw new ArgumentNullException(nameof(manager));
}
int code;
if (!int.TryParse(token, out code))
{
return false;
}
var securityToken = await manager.CreateSecurityTokenAsync(user);
var modifier = await GetUserModifierAsync(purpose, manager, user);
return securityToken != null && Rfc6238AuthenticationService.ValidateCode(securityToken, code, modifier);
}
或者
public virtual async Task<bool> ValidateAsync(string purpose, string token, UserManager<TUser> manager, TUser user)
{
try
{
var unprotectedData = Protector.Unprotect(Convert.FromBase64String(token));
var ms = new MemoryStream(unprotectedData);
using (var reader = ms.CreateReader())
{
var creationTime = reader.ReadDateTimeOffset();
var expirationTime = creationTime + Options.TokenLifespan;
if (expirationTime < DateTimeOffset.UtcNow)
{
return false;
}
var userId = reader.ReadString();
var actualUserId = await manager.GetUserIdAsync(user);
if (userId != actualUserId)
{
return false;
}
var purp = reader.ReadString();
if (!string.Equals(purp, purpose))
{
return false;
}
var stamp = reader.ReadString();
if (reader.PeekChar() != -1)
{
return false;
}
if (manager.SupportsUserSecurityStamp)
{
return stamp == await manager.GetSecurityStampAsync(user);
}
return stamp == "";
}
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
// Do not leak exception
}
return false;
}
一旦成功验证令牌身份系统进一步更新与新SecurityStamp
用户详细信息。回答您的问题
回答1 - 令牌不存储并且邮件中的链接立即生效。我有完整的测试生产系统,我和用户都不必等待链接处于活动状态。
Ans 2-我认为默认值是1天。您可以通过添加以下代码ApplicationUserManager
类
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>
(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = TimeSpan.FromHours(1) //Any custom TimeSpan
};
}
答3 Create
方法改变它 - 仅1将工作即无论用户点击第一个因为安全戳更改后,它就会失效2个其他电子邮件令牌。
希望这会有所帮助。
A谢谢你的详细解答 – LP13
你能检查我的答案吗?我错过了什么 ? –