在 Asp.Net Core 中使用短信服务而不是电子邮件重置密码

Reset password using SMS service instead of Email in Asp.Net Core

我想创建一个 Api 端点以通过短信发送密码重置令牌。

当我们使用userManager.GeneratePasswordResetTokenAsync(user)生成token时,token是一个很长的字符串,通常用在Email信息中。此消息嵌入一个包含令牌作为参数的 link 并发送给用户。用户点击 link 然后可以更改密码。

现在,我有这个问题:

根据我的经验,要重置用户密码,您可以通过发送确认 6 位字符串来验证用户。

对于这种情况,您将遵循以下内容:

  1. 创建一个端点以通过短信重置密码(在此操作中,您应该生成 6 位字符串并将值设置到缓存(Redis 等)中,并具有有限的生命周期(例如 1 分钟),然后发送通过短信发送给用户 phone 号码的值。
  2. 您将有一个接收 6 位字符串作为 confirmSMS 的端点,它检查该用户的缓存并使用缓存中的现有值验证输入值
  3. 如果验证结果没有问题,您应该允许用户更改 his/her 密码。

请注意,GeneratePasswordResetTokenAsyncGenerateChangeEmailTokenAsync 和类似方法使用 GenerateUserTokenAsync(user, provider, purpose) 并在后台指定提供程序和目的。

我们可以使用GenerateUserTokenAsync(user, provider, purpose)按照我们想要的方式生成令牌。所以这将是我的终点:

    [HttpPost("sendResetPasswordToken")]
    [ServiceFilter(typeof(ModelValidationFilter))]
    public async Task<IActionResult> SendChangePasswordToken([FromBody] SendChangePasswordTokenDto dto)
    {
        var user = await _userManager.FindByNameAsync(dto.UserName);
        if (user is null)
            return UnprocessableEntity("something went wrong, contact support to resolve the problem");


        var token = await _userManager.GenerateUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordPurpose");
        _SMSManager.SendResetPasswordToken(token, user.PhoneNumber);
        return NoContent();
    }

我们将提供者参数设置为 TokenOptions.DefaultPhoneProvider,这是一个默认的 phone 令牌提供者,并将目的参数设置为 "ResetPasswordPurpose",这是一个指示令牌用途的字符串。

为了验证此令牌,我们使用 VerifyUserTokenAsync(user, provider, purpose, token) 并提供适当的参数。所以这是我的 ResetPassword 端点:

    [HttpPost("resetPassword")]
    [ServiceFilter(typeof(ModelValidationFilter))]
    public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordDto dto)
    {
        var user = await _userManager.FindByNameAsync(dto.SSN);

        if(user is null)
            return UnprocessableEntity("invalid user token");//actually user not found

        var tokenVerified = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultPhoneProvider, "ResetPasswordPurpose", dto.Token);
        if (!tokenVerified)
            return UnprocessableEntity("invalid user token");

        var token = await _userManager.GeneratePasswordResetTokenAsync(user);//new token for reseting password
        var result = await  _userManager.ResetPasswordAsync(user, token, dto.NewPassword);
        if (!result.Succeeded)
            return UnprocessableEntity("weak password");

        return NoContent();
    }