C# 如何从ASP.NET Core中的密码重置令牌中检索用户?
我有一个ASP.NET Core 2.1 web应用程序,正在添加忘记密码功能。我看了几个例子,它们似乎采取了两种方法中的一种。第一种方法是在密码重置url中包含用户id或用户电子邮件以及密码重置令牌。第二种方法是在密码重置url中仅包含密码重置令牌,然后要求用户在尝试更改密码()时输入标识信息(如电子邮件)。是否有一种方法可以查找仅给定密码重置令牌的用户 我的团队负责人要求我只传递密码重置url中的令牌,然后查找用户。我最初的研究让我相信,我必须手动记录用户id和令牌关系,但我希望有一些内置的东西。我已经查看了,但是没有找到任何方法来检索给定令牌的用户 下面是一些将用户id嵌入密码重置URL()的示例代码:C# 如何从ASP.NET Core中的密码重置令牌中检索用户?,c#,asp.net-core,asp.net-core-identity,forgot-password,C#,Asp.net Core,Asp.net Core Identity,Forgot Password,我有一个ASP.NET Core 2.1 web应用程序,正在添加忘记密码功能。我看了几个例子,它们似乎采取了两种方法中的一种。第一种方法是在密码重置url中包含用户id或用户电子邮件以及密码重置令牌。第二种方法是在密码重置url中仅包含密码重置令牌,然后要求用户在尝试更改密码()时输入标识信息(如电子邮件)。是否有一种方法可以查找仅给定密码重置令牌的用户 我的团队负责人要求我只传递密码重置url中的令牌,然后查找用户。我最初的研究让我相信,我必须手动记录用户id和令牌关系,但我希望有一些内置的
我相信你不可能做到,你可以通过用户电子邮件,然后找到它,在你的代码中寻找用户
public async Task<IActionResult> ResetPassword([FromBody]ResetPasswordViewModel model)
{
if (string.IsNullOrEmpty(model.Token) || string.IsNullOrEmpty(model.Email))
{
return RedirectToAction("Index", "Error", new { statusCode = AppStatusCode.NotFound });
}
var isResetTokenValid = await _userManager.CheckValidResetPasswordToken(model.Token, model.Email);
if (!isResetTokenValid || string.IsNullOrEmpty(model.Email))
{
return StatusCode(AppStatusCode.ResetPassTokenExpire);
}
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
return Ok();
}
await _userManager.ResetPasswordAsync(user, model.Token, model.Password);
return Ok();
}
公共异步任务重置密码([FromBody]ResetPasswordViewModel)
{
if(string.IsNullOrEmpty(model.Token)| string.IsNullOrEmpty(model.Email))
{
返回RedirectToAction(“Index”,“Error”,new{statusCode=AppStatusCode.NotFound});
}
var isResetTokenValid=wait_userManager.CheckValidResetPasswordToken(model.Token,model.Email);
如果(!isResetTokenValid | | string.IsNullOrEmpty(model.Email))
{
返回状态码(AppStatusCode.ResetPassTokenExpire);
}
var user=await\u userManager.findbyemailsync(model.Email);
if(user==null)
{
返回Ok();
}
wait\u userManager.ResetPasswordAsync(用户、模型、令牌、模型、密码);
返回Ok();
}
您可以查看实现详细信息有一种方法可以从密码重置令牌获取
用户ID
,但在我看来,这很棘手,而且工作量很大
默认设置是什么
如果您有如下代码
services.AddIdentity,用于生成用于重置密码、更改电子邮件和更改电话号码选项的令牌,以及用于生成双因素身份验证令牌的令牌
DataProtectorTokenProvider
PhoneNumberTokenProvider
EmailTokenProvider
认证TortokenProvider
第一个,DataProtectorTokenProvider,是我们正在寻找的。它使用数据保护来序列化/加密这些令牌
在DataProtectorTokenProvider
中,其保护器是
令牌是如何生成的
如果查看DataProtectorTokenProvider
中的方法,可以看出令牌由以下部分组成:
- 令牌创建的Utc时间戳(
DateTimeOffset.UtcNow
)
userId
- 目的字符串
- 安全戳(如果支持)
generate方法将所有这些连接起来,将它们转换为字节数组,并调用内部的保护器来保护/加密有效负载。最后,有效负载被转换为基本64字符串
如何获取用户Id
要从令牌获取用户ID
,您需要执行反向工程:
- 将令牌从基64字符串转换回字节数组
- 调用内部的保护程序来取消对字节数组的保护/解密
- 读取Utc时间戳
- 读取
userId
这里棘手的部分是如何获得用于生成这些令牌的相同的DataProtector
如何获取默认数据保护器
由于默认的DataProtectorTokenProvider
已消失在管道中,因此我能想到的获得相同的DataProtector
的唯一方法是使用默认的DataProtectorTokenProvider
创建一个名为“DataProtectorTokenProvider”的默认保护器,用于生成令牌
公共类GetResetPasswordViewModelHandler:IRequestHandler
{
...
专用只读IDataProtector_dataProtector;
公共GetResetPasswordViewModelHandler(。。。,
IDataProtectionProvider(数据保护提供程序)
{
...
_dataProtector=dataProtectionProvider.CreateProtector(“DataProtectorTokenProvider”);
//或
//dataProtectionProvider.CreateProtector(新的DataProtectionTokenProviderOptions().Name);
}
公共异步任务句柄(GetResetPasswordViewModel查询,…)
{
//密码重置令牌来自query.ResetToken
var resetTokenArray=Convert.FromBase64String(query.ResetToken);
var unprotectedResetTokenArray=\u dataProtector.Unprotect(resetTokenArray);
使用(var ms=new MemoryStream(unprotectedResetTokenArray))
{
使用(变量读取器=新二进制读取器(ms))
{
//读取创建UTC时间戳
reader.ReadInt64();
//然后您可以读取用户ID!
var userId=reader.ReadString();
...
}
}
...
}
}
屏幕截图:
我的2美分
似乎要做很多工作,只要试着从密码重置令牌读取userId
。我知道您的团队负责人可能不想在密码重置链接上公开用户id,或者他认为这是多余的,因为重置令牌具有用户id
如果您使用integer来表示用户ID
,并且不想将其公开,我会将其更改为GUID
如果您必须使用integer作为您的用户ID
,我只需在用户配置文件中创建一列类型为unique_identifier的列(我称之为PublicToken),并使用该列作为标识符
public async Task<IActionResult> ResetPassword([FromBody]ResetPasswordViewModel model)
{
if (string.IsNullOrEmpty(model.Token) || string.IsNullOrEmpty(model.Email))
{
return RedirectToAction("Index", "Error", new { statusCode = AppStatusCode.NotFound });
}
var isResetTokenValid = await _userManager.CheckValidResetPasswordToken(model.Token, model.Email);
if (!isResetTokenValid || string.IsNullOrEmpty(model.Email))
{
return StatusCode(AppStatusCode.ResetPassTokenExpire);
}
var user = await _userManager.FindByEmailAsync(model.Email);
if (user == null)
{
return Ok();
}
await _userManager.ResetPasswordAsync(user, model.Token, model.Password);
return Ok();
}