ASP.NET Identity reset password

前端 未结 10 1131
无人及你
无人及你 2020-12-02 05:09

How can I get the password of a user in the new ASP.NET Identity system? Or how can I reset without knowing the current one (user forgot password)?

10条回答
  •  感情败类
    2020-12-02 05:26

    I think Microsoft guide for ASP.NET Identity is a good start.

    https://docs.microsoft.com/en-us/aspnet/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity

    Note:

    If you do not use AccountController and wan't to reset your password, use Request.GetOwinContext().GetUserManager();. If you dont have the same OwinContext you need to create a new DataProtectorTokenProvider like the one OwinContext uses. By default look at App_Start -> IdentityConfig.cs. Should look something like new DataProtectorTokenProvider(dataProtectionProvider.Create("ASP.NET Identity"));.

    Could be created like this:

    Without Owin:

    [HttpGet]
    [AllowAnonymous]
    [Route("testReset")]
    public IHttpActionResult TestReset()
    {
        var db = new ApplicationDbContext();
        var manager = new ApplicationUserManager(new UserStore(db));
        var provider = new DpapiDataProtectionProvider("SampleAppName");
        manager.UserTokenProvider = new DataProtectorTokenProvider(
            provider.Create("SampleTokenName"));
    
        var email = "test@test.com";
    
        var user = new ApplicationUser() { UserName = email, Email = email };
    
        var identityUser = manager.FindByEmail(email);
    
        if (identityUser == null)
        {
            manager.Create(user);
            identityUser = manager.FindByEmail(email);
        }
    
        var token = manager.GeneratePasswordResetToken(identityUser.Id);
        return Ok(HttpUtility.UrlEncode(token));
    }
    
    [HttpGet]
    [AllowAnonymous]
    [Route("testReset")]
    public IHttpActionResult TestReset(string token)
    {
        var db = new ApplicationDbContext();
        var manager = new ApplicationUserManager(new UserStore(db));
        var provider = new DpapiDataProtectionProvider("SampleAppName");
        manager.UserTokenProvider = new DataProtectorTokenProvider(
            provider.Create("SampleTokenName"));
        var email = "test@test.com";
        var identityUser = manager.FindByEmail(email);
        var valid = Task.Run(() => manager.UserTokenProvider.ValidateAsync("ResetPassword", token, manager, identityUser)).Result;
        var result = manager.ResetPassword(identityUser.Id, token, "TestingTest1!");
        return Ok(result);
    }
    

    With Owin:

    [HttpGet]
    [AllowAnonymous]
    [Route("testResetWithOwin")]
    public IHttpActionResult TestResetWithOwin()
    {
        var manager = Request.GetOwinContext().GetUserManager();
    
        var email = "test@test.com";
    
        var user = new ApplicationUser() { UserName = email, Email = email };
    
        var identityUser = manager.FindByEmail(email);
    
        if (identityUser == null)
        {
            manager.Create(user);
            identityUser = manager.FindByEmail(email);
        }
    
        var token = manager.GeneratePasswordResetToken(identityUser.Id);
        return Ok(HttpUtility.UrlEncode(token));
    }
    
    [HttpGet]
    [AllowAnonymous]
    [Route("testResetWithOwin")]
    public IHttpActionResult TestResetWithOwin(string token)
    {
        var manager = Request.GetOwinContext().GetUserManager();
    
        var email = "test@test.com";
        var identityUser = manager.FindByEmail(email);
        var valid = Task.Run(() => manager.UserTokenProvider.ValidateAsync("ResetPassword", token, manager, identityUser)).Result;
        var result = manager.ResetPassword(identityUser.Id, token, "TestingTest1!");
        return Ok(result);
    }
    

    The DpapiDataProtectionProvider and DataProtectorTokenProvider needs to be created with the same name for a password reset to work. Using Owin for creating the password reset token and then creating a new DpapiDataProtectionProvider with another name won't work.

    Code that I use for ASP.NET Identity:

    Web.Config:

    
    

    AccountController.cs:

    [Route("RequestResetPasswordToken/{email}/")]
    [HttpGet]
    [AllowAnonymous]
    public async Task GetResetPasswordToken([FromUri]string email)
    {
        if (!ModelState.IsValid)
            return BadRequest(ModelState);
    
        var user = await UserManager.FindByEmailAsync(email);
        if (user == null)
        {
            Logger.Warn("Password reset token requested for non existing email");
            // Don't reveal that the user does not exist
            return NoContent();
        }
    
        //Prevent Host Header Attack -> Password Reset Poisoning. 
        //If the IIS has a binding to accept connections on 80/443 the host parameter can be changed.
        //See https://security.stackexchange.com/a/170759/67046
        if (!ConfigurationManager.AppSettings["AllowedHosts"].Split(',').Contains(Request.RequestUri.Host)) {
                Logger.Warn($"Non allowed host detected for password reset {Request.RequestUri.Scheme}://{Request.Headers.Host}");
                return BadRequest();
        }
    
        Logger.Info("Creating password reset token for user id {0}", user.Id);
    
        var host = $"{Request.RequestUri.Scheme}://{Request.Headers.Host}";
        var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
        var callbackUrl = $"{host}/resetPassword/{HttpContext.Current.Server.UrlEncode(user.Email)}/{HttpContext.Current.Server.UrlEncode(token)}";
    
        var subject = "Client - Password reset.";
        var body = "" +
                   "

    Password reset

    " + $"

    Hi {user.FullName}, please click this link to reset your password

    " + ""; var message = new IdentityMessage { Body = body, Destination = user.Email, Subject = subject }; await UserManager.EmailService.SendAsync(message); return NoContent(); } [HttpPost] [Route("ResetPassword/")] [AllowAnonymous] public async Task ResetPasswordAsync(ResetPasswordRequestModel model) { if (!ModelState.IsValid) return NoContent(); var user = await UserManager.FindByEmailAsync(model.Email); if (user == null) { Logger.Warn("Reset password request for non existing email"); return NoContent(); } if (!await UserManager.UserTokenProvider.ValidateAsync("ResetPassword", model.Token, UserManager, user)) { Logger.Warn("Reset password requested with wrong token"); return NoContent(); } var result = await UserManager.ResetPasswordAsync(user.Id, model.Token, model.NewPassword); if (result.Succeeded) { Logger.Info("Creating password reset token for user id {0}", user.Id); const string subject = "Client - Password reset success."; var body = "" + "

    Your password for Client was reset

    " + $"

    Hi {user.FullName}!

    " + "

    Your password for Client was reset. Please inform us if you did not request this change.

    " + ""; var message = new IdentityMessage { Body = body, Destination = user.Email, Subject = subject }; await UserManager.EmailService.SendAsync(message); } return NoContent(); } public class ResetPasswordRequestModel { [Required] [Display(Name = "Token")] public string Token { get; set; } [Required] [Display(Name = "Email")] public string Email { get; set; } [Required] [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 10)] [DataType(DataType.Password)] [Display(Name = "New password")] public string NewPassword { get; set; } [DataType(DataType.Password)] [Display(Name = "Confirm new password")] [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] public string ConfirmPassword { get; set; } }

提交回复
热议问题