ASP.NET Identity reset password

前端 未结 10 1029
无人及你
无人及你 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:15

    On your UserManager, first call GeneratePasswordResetTokenAsync. Once the user has verified his identity (for example by receiving the token in an email), pass the token to ResetPasswordAsync.

    0 讨论(0)
  • 2020-12-02 05:24

    I did a little investigation and the solution that works for me was a mix of a few solutions founded in this post.

    I'm basically compiling this solution and I'm posting what works for me. In my case, I'm don't want to use any token from .net core.

    public async Task ResetPassword(string userId, string password)
    {
        var user = await _userManager.FindByIdAsync(userId);
        var hashPassword= _userManager.PasswordHasher.HashPassword(user, password);
        user.PasswordHash = passwordHash;
        await _userManager.UpdateAsync(user);
    
    }
    
    0 讨论(0)
  • 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<ApplicationUserManager>();. 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<ApplicationUser>(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<ApplicationUser>(db));
        var provider = new DpapiDataProtectionProvider("SampleAppName");
        manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
            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<ApplicationUser>(db));
        var provider = new DpapiDataProtectionProvider("SampleAppName");
        manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
            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<ApplicationUserManager>();
    
        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<ApplicationUserManager>();
    
        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:

    <add key="AllowedHosts" value="example.com,example2.com" />
    

    AccountController.cs:

    [Route("RequestResetPasswordToken/{email}/")]
    [HttpGet]
    [AllowAnonymous]
    public async Task<IHttpActionResult> 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 = "<html><body>" +
                   "<h2>Password reset</h2>" +
                   $"<p>Hi {user.FullName}, <a href=\"{callbackUrl}\"> please click this link to reset your password </a></p>" +
                   "</body></html>";
    
        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<IHttpActionResult> 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 = "<html><body>" +
                       "<h1>Your password for Client was reset</h1>" +
                       $"<p>Hi {user.FullName}!</p>" +
                       "<p>Your password for Client was reset. Please inform us if you did not request this change.</p>" +
                       "</body></html>";
    
            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; }
    }
    
    0 讨论(0)
  • 2020-12-02 05:28

    Deprecated

    This was the original answer. It does work, but has a problem. What if AddPassword fails? The user is left without a password.

    The original answer: we can use three lines of code:

    UserManager<IdentityUser> userManager = 
        new UserManager<IdentityUser>(new UserStore<IdentityUser>());
    
    userManager.RemovePassword(userId);
    
    userManager.AddPassword(userId, newPassword);
    

    See also: http://msdn.microsoft.com/en-us/library/dn457095(v=vs.111).aspx

    Now Recommended

    It's probably better to use the answer that EdwardBrey proposed and then DanielWright later elaborated with a code sample.

    0 讨论(0)
  • 2020-12-02 05:32

    In case of password reset, it is recommended to reset it through sending password reset token to registered user email and ask user to provide new password. If have created a easily usable .NET library over Identity framework with default configuration settins. You can find details at blog link and source code at github.

    0 讨论(0)
  • 2020-12-02 05:33

    In current release

    Assuming you have handled the verification of the request to reset the forgotten password, use following code as a sample code steps.

    ApplicationDbContext =new ApplicationDbContext()
    String userId = "<YourLogicAssignsRequestedUserId>";
    String newPassword = "<PasswordAsTypedByUser>";
    ApplicationUser cUser = UserManager.FindById(userId);
    String hashedNewPassword = UserManager.PasswordHasher.HashPassword(newPassword);
    UserStore<ApplicationUser> store = new UserStore<ApplicationUser>();            
    store.SetPasswordHashAsync(cUser, hashedNewPassword);
    

    In AspNet Nightly Build

    The framework is updated to work with Token for handling requests like ForgetPassword. Once in release, simple code guidance is expected.

    Update:

    This update is just to provide more clear steps.

    ApplicationDbContext context = new ApplicationDbContext();
    UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context);
    UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(store);
    String userId = User.Identity.GetUserId();//"<YourLogicAssignsRequestedUserId>";
    String newPassword = "test@123"; //"<PasswordAsTypedByUser>";
    String hashedNewPassword = UserManager.PasswordHasher.HashPassword(newPassword);                    
    ApplicationUser cUser = await store.FindByIdAsync(userId);
    await store.SetPasswordHashAsync(cUser, hashedNewPassword);
    await store.UpdateAsync(cUser);
    
    0 讨论(0)
提交回复
热议问题