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

그만큼 DpapiDataProtectionProvider및 DataProtectorTokenProvider요구 사항은 작업에 암호 재설정에 대해 동일한 이름으로 생성합니다. 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.