ASP.NET ID 재설정 암호


95

새 ASP.NET Identity System에서 사용자의 암호를 얻으려면 어떻게해야합니까? 또는 현재 암호를 모르고 어떻게 재설정 할 수 있습니까 (사용자가 암호를 잊어 버림)?

답변:


102

현재 릴리스에서

잊어 버린 비밀번호 재설정 요청에 대한 확인을 처리했다고 가정하면 다음 코드를 샘플 코드 단계로 사용합니다.

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);

AspNet Nightly Build에서

ForgetPassword와 같은 요청을 처리하기 위해 토큰과 함께 작동하도록 프레임 워크가 업데이트되었습니다. 출시되면 간단한 코드 안내가 예상됩니다.

최신 정보:

이 업데이트는 더 명확한 단계를 제공하기위한 것입니다.

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);

버전 1.1이 언제 출시되는지 알고 계십니까?
graycrow

아직 알파 버전이며 1.0이 방금 출시되었습니다. 따라서 몇 달을 가정하십시오. myget.org/gallery/aspnetwebstacknightly
jd4u

11
이상하게도 store.SetPasswordHashAsync (cUser, hashedNewPassword) 메서드 호출이 작동하지 않았습니다. 대신 수동으로 cUser.PasswordHash = hashedNewPassword를 설정 한 다음 UserManager.UpdateAsync (user);
Andy Mehalick 2010 년

1
코드가 작동하지 않는 것은 사용자 검색 컨텍스트와 스토어 컨텍스트가 다른 경우에만 가능합니다. 코드는 정확하지 않은 샘플 단계 일뿐입니다. 다른 사람들을 위해이 문제를 피하기 위해 곧 답변을 업데이트 할 것입니다.
jd4u

1
프레임 워크 1은 제공하지 않습니다. 그러나 Framework 2-alpha에는 암호 재설정 요청을 처리하기위한 간단한 프로세스를 제공 할 수있는 기능이 거의 없습니다. aspnetidentity.codeplex.com
jd4u

138

또는 현재 암호를 모르고 어떻게 재설정 할 수 있습니까 (사용자가 암호를 잊어 버림)?

UserManager를 사용하여 비밀번호를 변경하고 싶지만 사용자의 현재 비밀번호를 제공하지 않으려는 경우 비밀번호 재설정 토큰을 생성 한 다음 대신 즉시 사용할 수 있습니다.

string resetToken = await UserManager.GeneratePasswordResetTokenAsync(model.Id);
IdentityResult passwordChangeResult = await UserManager.ResetPasswordAsync(model.Id, resetToken, model.NewPassword);

8
이것은 새 비밀번호를 설정하는 가장 좋고 깨끗한 방법입니다. 허용되는 답변의 문제는 암호 해셔에 직접 액세스하여 암호 복잡성 유효성 검사를 우회한다는 것입니다.
Chris

6
참고로 'IUserTokenProvider가 등록되지 않았습니다'라는 오류 메시지가 표시 될 수 있습니다. 위의 논리를 사용하면. 이 stackoverflow.com/questions/22629936/…을 참조하십시오 .
Prasad Kanaparthi

1
이것은 버전 2의 Microsoft.AspNet.Identity에서만 작동합니다. 당신은 버전 1의 GeneratePasswordResetTokenAsync 방법을 찾을 수 없습니다
romanoza

답변 주셔서 감사합니다. 제게는 매력처럼 작동합니다.
Thomas.Benz

4
Invalid Token을 받으면 사용자 의이SecurityStamp null이 아닌지 확인하십시오 . 이는 다른 데이터베이스에서 마이그레이션 된 사용자 또는 UserManager.CreateAsync()방법을 통해 생성되지 않은 사용자에게 발생할 수 있습니다 .
알리슨

70

사용되지 않음

이것이 원래의 대답이었습니다. 작동하지만 문제가 있습니다. 만약에 AddPassword실패? 사용자는 암호없이 남겨집니다.

원래 답변 : 세 줄의 코드를 사용할 수 있습니다.

UserManager<IdentityUser> userManager = 
    new UserManager<IdentityUser>(new UserStore<IdentityUser>());

userManager.RemovePassword(userId);

userManager.AddPassword(userId, newPassword);

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

지금 추천

그것은 그 해답 사용하는 것이 아마도 더 나은 EdwardBrey 제안 하고 DanielWright 나중에 정교 코드 샘플을.


1
이것에 대해 신에게 감사합니다. 나는 이것을 볼 때까지 새로운 사용자 저장소를 만들어야한다고 생각했습니다!
Luke

SQL에서 직접 수행 할 수있는 방법이 있습니까? DBA에게 실행 파일 대신 필요할 때 호출 할 sproc을 건네주고 싶습니다.
Mark Richman

@MarkRichman 새로운 질문입니다. 하지만 할 수있는 한 가지는 SQL Server에서 실행되는 생성 된 T-SQL을 검사하는 것입니다.
Shaun Luttin 2015

3
이 기능을 켜 놓은 상태에서 AddPassword가 실패 할 때마다 (즉, 암호 복잡성이 충분하지 않음) 사용자는 암호없이 남게됩니다.
Chris

1
비즈니스 규칙을 우회하지 않는 가장 깔끔한 접근 방식은 (비밀번호 해시에 직접 액세스 할 때 비밀번호 복잡성 검증이 없기 때문에) Daniel Wright가 제안한 것입니다.
Chris

29

당신에 UserManager먼저 전화 GeneratePasswordResetTokenAsync을 . 사용자가 자신의 신원을 확인한 후 (예 : 이메일로 토큰 수신) 토큰을 ResetPasswordAsync에 전달합니다 .


1
ResetPasswordAsync에 사용자 ID가 필요한 이유와 사용자가 토큰과 함께 표시 될 때 사용자로부터 가져 오는 합리적인 방법을 알아 내려고합니다. GeneratePasswordReset은 150자가 넘는 토큰을 사용합니다 ... 사용자 ID를 암호화하여 저장하기에 충분할 것 같으므로 직접 구현할 필요가 없습니다. :(
pettys

사용자 ID에 대해 ID 데이터베이스에 재설정 토큰을 입력 할 수 있도록 사용자 ID를 요청한다고 가정합니다. 이렇게하지 않으면 프레임 워크가 토큰이 유효한지 어떻게 알 수 있습니다. User.Identity.GetUserId () 등을 사용하여 사용자 ID를 가져올 수 있어야합니다.
Ryan Buddicom 2015 년

1
사용자 ID를 요구하는 것은 API 부분에서 어리석은 선택이며, 토큰은 ResetPassword (async)가 호출 될 때 이미 데이터베이스에 있으며 입력에 대해 유효성을 검사하는 데 충분해야합니다.
Filip

@Filip, ResetPasswordAsync사용자 ID 사용 의 장점은 ID 공급자가 토큰이 아닌 사용자 ID 만 인덱싱하면된다는 것입니다. 이렇게하면 사용자가 많을 때 더 잘 확장 할 수 있습니다.
Edward Brey 2015

1
@Edward Brey 음, 재설정 호출을 위해 사용자 ID를 어떻게 가져 옵니까?
Filip

2
string message = null;
//reset the password
var result = await IdentityManager.Passwords.ResetPasswordAsync(model.Token, model.Password);
if (result.Success)
{
    message = "The password has been reset.";
    return RedirectToAction("PasswordResetCompleted", new { message = message });
}
else
{
    AddErrors(result);
}

이 코드 조각은 github에서 사용할 수 있는 AspNetIdentitySample 프로젝트에서 가져온 것입니다.


2

방법 만들기 UserManager<TUser, TKey>

public Task<IdentityResult> ChangePassword(int userId, string newPassword)
{
     var user = Users.FirstOrDefault(u => u.Id == userId);
     if (user == null)
          return new Task<IdentityResult>(() => IdentityResult.Failed());

     var store = Store as IUserPasswordStore<User, int>;
     return base.UpdatePassword(store, user, newPassword);
}

1

비밀번호 재설정의 경우 등록 된 사용자 이메일로 비밀번호 재설정 토큰을 전송하여 재설정하고 사용자에게 새 비밀번호 제공을 요청하는 것이 좋습니다. 기본 구성 설정으로 Identity 프레임 워크를 통해 쉽게 사용할 수있는 .NET 라이브러리를 만든 경우. 자세한 내용은 블로그 링크 및 github의 소스 코드 에서 확인할 수 있습니다 .


1

ASP.NET Identity에 대한 Microsoft 가이드가 좋은 시작이라고 생각합니다.

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

노트 :

AccountController를 사용하지 않고 비밀번호를 재설정하지 않으려면 Request.GetOwinContext().GetUserManager<ApplicationUserManager>();. 동일한 OwinContext가 없다면 사용하는 DataProtectorTokenProvider것과 같은 새로운 것을 만들어야 OwinContext합니다. 기본적으로 App_Start -> IdentityConfig.cs. 다음과 같이 보일 것 new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));입니다.

다음과 같이 만들 수 있습니다.

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);
}

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);
}

그만큼 DpapiDataProtectionProviderDataProtectorTokenProvider요구 사항은 작업에 암호 재설정에 대해 동일한 이름으로 생성합니다. Owin을 사용하여 암호 재설정 토큰을 만든 다음 DpapiDataProtectionProvider다른 이름 으로 새로 만드는 것은 작동하지 않습니다.

ASP.NET ID에 사용하는 코드 :

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; }
}

1

저는 약간의 조사를했고 저에게 적합한 솔루션은이 게시물에서 발견 한 몇 가지 솔루션의 혼합이었습니다.

나는 기본적 으로이 솔루션을 컴파일하고 있으며 나를 위해 작동하는 것을 게시하고 있습니다. 제 경우에는 .net 코어의 토큰을 사용하고 싶지 않습니다.

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);

}

1

웹 API에 대한 Asp.Net Core Identity 사용에서 암호를 재설정하는 가장 좋은 방법입니다.

참고 * : Error () 및 Result ()는 내부 용으로 생성됩니다. 원하는대로 반환 할 수 있습니다.

        [HttpPost]
        [Route("reset-password")]
        public async Task<IActionResult> ResetPassword(ResetPasswordModel model)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);
            try
            {
                if (model is null)
                    return Error("No data found!");


                var user = await _userManager.FindByIdAsync(AppCommon.ToString(GetUserId()));
                if (user == null)
                    return Error("No user found!");

                Microsoft.AspNetCore.Identity.SignInResult checkOldPassword =
                    await _signInManager.PasswordSignInAsync(user.UserName, model.OldPassword, false, false);

                if (!checkOldPassword.Succeeded)
                    return Error("Old password does not matched.");

                string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);
                if (string.IsNullOrEmpty(resetToken))
                    return Error("Error while generating reset token.");

                var result = await _userManager.ResetPasswordAsync(user, resetToken, model.Password);

                if (result.Succeeded)
                    return Result();
                else
                    return Error();
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }

1
이것은 Fx v 4.5에서도 저에게 효과적이었습니다. 다른 솔루션은 작동하지 않았습니다. 근본적으로 이것은 훨씬 더 간단했습니다. 모든 메소드가 ID를 허용하므로 사용자를 가져올 필요조차 없습니다. 관리자 인터페이스에서 일시적인 일회성 재설정을 위해 필요했기 때문에 모든 오류 검사가 필요하지 않았습니다.
Steve Hiner
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.