programing

확인 이메일의 ASP.NET 핵심 ID 토큰이 잘못되었습니다.

showcode 2023. 4. 5. 22:30
반응형

확인 이메일의 ASP.NET 핵심 ID 토큰이 잘못되었습니다.

이것은 확인 이메일의 이 aspnet ID 무효 토큰과 매우 유사한 질문이지만, 새로운 ASP를 사용하고 있기 때문에 해결 방법이 유효하지 않습니다.ASP를 포함한 NET Core 1.0NET 코어 아이덴티티

저의 시나리오는 다음과 같습니다.

  1. 백엔드(ASP).NET Core) 패스워드 리셋 이메일을 링크와 함께 보내는 기능이 있습니다.링크를 생성하려면 ID를 사용하여 코드를 생성해야 합니다.이런 거.

    public async Task SendPasswordResetEmailAsync(string email)
    {
        //_userManager is an instance of UserManager<User>
        var userEntity = await _userManager.FindByNameAsync(email);
        var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);
        var link = Url.Action("MyAction", "MyController", new { email = email, code = tokenGenerated }, protocol: HttpContext.Request.Scheme);
         //this is my service that sends an email to the user containing the generated password reset link
         await _emailService.SendPasswordResetEmailAsync(userEntity , link);
    }
    

    그러면 다음 링크가 포함된 이메일이 생성됩니다.

    http://myapp:8080/passwordreset?code=CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX+5Cq1msu9zgkuI32Iz9x/5uE1B9fKFp4tZFFy6lBTseDFTHSJxwtGu+jHX5cajptUBiVqIChiwoTODh7ei4+MOkX7rdNVBMhG4jOZWqqtZ5J30gXr/JmltbYxqOp4JLs8V05BeKDbbVO/Fsq5+jebokKkR5HEJU+mQ5MLvNURsJKRBbI3qIllj1RByXt9mufGRE3wmQf2fgKBkAL6VsNgB8w==

  2. 그런 다음 AngularJs 어플리케이션은 새로운 비밀번호를 입력하고 확인하는 폼을 사용하여 뷰를 표시하고 URL에 새로운 비밀번호와 쿼리 파라미터에서 얻은 코드를 포함한 JSON 객체를 배치합니다.

  3. 마지막으로 백엔드는 PUT 요청을 받고 코드를 잡아 다음과 같이 Identity를 사용하여 검증합니다.

    [HttpPut]
    [AllowAnonymous]
    [Route("api/password/{email}")]
    public async Task<IActionResult> SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset)
    {
        //some irrelevant validatoins here
        await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);
        return Ok();
    }
    

문제는 Identity가 다음과 같이 응답한다는 것입니다.

유효하지 않은 토큰

에러입니다. 문제는 코드가 일치하지 않고 위의 코드가 다음과 같이 PUT 요청의 JSON 개체로 다시 수신된다는 것입니다.

CfDJ8JBnWaVj6h1PtqlmlJaH57r9TRA5j7Ij1BVyeBUpqX 5Cq1msu9zgkuI32Iz9x/5uE1B9fKFp4tZFFy6lBTseDFTHSJxwtGu jHX5cajptUBiVqIChiwoTODh7ei4 MOkX7rdNVBMhG4jOZWqqtZ5J30gXr/JmltbYxqOp4JLs8V05BeKDbbVO/Fsq5 jebokKkR5HEJU mQ5MLvNURsJKRBbI3qIllj1RByXt9mufGRE3wmQf2fgKBkAL6VsNgB8w==

「」가 장소에 주의해 .+에는 공백이 .그 때문에 아이덴티티는 토큰이 다르다고 생각하게 됩니다.어떤 이유로 Angular는 인코딩된 다른 방법으로 URL 쿼리 파라미터를 디코딩하고 있습니다.

어떻게 해결할까요?

이 답변은 https://stackoverflow.com/a/31297879/2948212에서 올바른 방향을 제시해 주었습니다.하지만 제가 말했듯이, 그것은 다른 버전이었고 지금은 약간 다른 해결책입니다.

답은 동일합니다.토큰을 base 64 url로 인코딩한 후 base 64 url로 디코딩합니다.그러면 Angular와 ASP 모두.NET Core는 동일한 코드를 가져옵니다.

는 또 가 있었다.Microsoft.AspNetCore.WebUtilities;

코드는 다음과 같습니다.

public async Task SendPasswordResetEmailAsync(string email)
{
    //_userManager is an instance of UserManager<User>
    var userEntity = await _userManager.FindByNameAsync(email);
    var tokenGenerated = await _userManager.GeneratePasswordResetTokenAsync(userEntity);
    byte[] tokenGeneratedBytes = Encoding.UTF8.GetBytes(tokenGenerated);
    var codeEncoded = WebEncoders.Base64UrlEncode(tokenGeneratedBytes);
    var link = Url.Action("MyAction", "MyController", new { email = email, code = codeEncoded }, protocol: HttpContext.Request.Scheme);
     //this is my service that sends an email to the user containing the generated password reset link
     await _emailService.SendPasswordResetEmailAsync(userEntity , link);
}

그리고 PUT 요청 중에 코드를 돌려받을 때

[HttpPut]
[AllowAnonymous]
[Route("api/password/{email}")]
public async Task<IActionResult> SendPasswordEmailResetRequestAsync(string email, [FromBody] PasswordReset passwordReset)
{
    //some irrelevant validatoins here
    await _myIdentityWrapperService.ResetPasswordAsync(email, passwordReset.Password, passwordReset.Code);
    return Ok();
}

//in MyIdentityWrapperService
public async Task ResetPasswordAsync(string email, string password, string code)
{
    var userEntity = await _userManager.FindByNameAsync(email);
    var codeDecodedBytes = WebEncoders.Base64UrlDecode(code);
    var codeDecoded = Encoding.UTF8.GetString(codeDecodedBytes);
    await _userManager.ResetPasswordAsync(userEntity, codeDecoded, password);
}

보니 과 같습니다.options.LowercaseQueryStrings = true;「 」를 설정하지 말아 .trueoptions.LowercaseQueryStrings그러면 유효성 검사 토큰의 무결성이 변경되어 잘못된 토큰 오류가 발생합니다.

// This allows routes to be in lowercase
services.AddRouting(options =>
{
     options.LowercaseUrls = true;
      options.LowercaseQueryStrings = false;
});

위의 답변을 시도해 보았지만 이 가이드가 도움이 되었습니다.기본적으로 코드를 인코딩해야 합니다.그렇지 않으면 이상한 버그가 발생합니다.요약하자면 다음과 같이 해야 합니다.

string code = HttpUtility.UrlEncode(UserManager.GenerateEmailConfirmationToken(userID));

그 후, 해당하는 경우는, 코드를 디코딩 합니다.

string decoded = HttpUtility.UrlDecode(code)

ASP에서 Confirm Email 페이지를 작성한 후Net Core 3.0 프로젝트에서도 같은 문제가 발생했습니다.

OnGetAsync in the method in the method in 。ConfirmEmail.cshtml.cs제제: :

code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));

" " " " " " " "code 붙습니다.callbackUrl URL은 "URL"을 사용하여 됩니다.HtmlEncoder.Default.Encode(callbackUrl)되며 디코딩이 이루어집니다code이메일을 확인하는 것과 같습니다.

갱신:

패스워드를 잊어버린 프로세스 중에codeBase64에 되어 있는 callbackUrl즉, Base64 디코딩이 필요합니다.

따라서 callbackUrl에 추가하기 전에 코드가 생성되는 위치에 다음 행을 추가하는 것이 좋습니다.

code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));

수정한 문제에 대한 링크입니다.

(이 투고에 의하면, https://stackoverflow.com/a/27943434/9869427)

reset Password Async(ID 매니저) "token invalid" 문제의 경우..."+"가 url의 공백이 되기 때문에...URI를 사용합니다.이스케이프 Uri String

예: sendResetPasswordByMailAsync에서

var token = "Aa+Bb Cc";
var encodedToken = Uri.EscapeDataString(token); 

encodedToken = "Aa%20Bb2B%Cc"

var url = $"http://localhost:4200/account/reset-password?email={email}&token={encodedToken}";
var mailContent= $"Please reset your password by <a href='{url}'>clicking here</a>.";

이제 링크를 클릭하면 "+"(%2B로 인코딩)로 올바른 URL로 이동합니다.당신의 토큰은 무효가 되지 않을 것입니다...

GCP에서 Cloud Run을 사용하여 웹 사이트를 호스팅할 때도 같은 문제가 발생했는데, 이 솔루션 중 어느 것도 나에게 효과가 없었습니다.

제 경우 데이터 보호 키가 인스턴스에 로컬로 저장되는 것이 문제였습니다.로그의 다음 엔트리가 문제를 시사하고 있습니다.

컨테이너 외부에서 유지되지 않을 수 있는 '/home/.aspnet/DataProtection-Keys' 디렉터리에 키 저장컨테이너가 파괴되면 보호된 데이터를 사용할 수 없습니다.

따라서 토큰은 발행된 인스턴스에 대해서만 유효했습니다.이 인스턴스는 사용자가 이메일로 보낸 링크를 클릭했을 때 이미 파기되었습니다.

솔루션은 다음과 같이 EntityFramework를 통한 데이터베이스와 같은 키에 분산 스토리지를 사용하는 방법은 다음과 같습니다.

using Microsoft.AspNetCore.DataProtection;
...
public void ConfigureServices(IServiceCollection services)
{
    services.AddDataProtection()
        .PersistKeysToDbContext<DbContext>();

    services.AddIdentity<User, IdentityRole>()
                .AddEntityFrameworkStores<AnotherDbContext>()
                .AddDefaultTokenProviders();
}

다양한 유형의 스토리지에 대한 자세한 내용은 여기에서 확인할 수 있습니다.

ASP Core 2.1에서도 같은 문제가 발생하여 머리를 긁적거리고 있었습니다.왜냐하면 어떤 인코딩/디코딩이code(token)은(는)통하지않았습니다.그리고 항상 유효하지 않은 토큰 오류가 있었습니다.userManager.ConfirmEmailAsync(user, code)


해결 방법: 문제는 사용자가 생성되지 않은 것이었음이 판명되었습니다.UserManagerdbcontext를 사용하여_dbContext.Users.AddAsync이 작성 방법을 로 대체한 후_userManager.CreateAsync암호화/삭제 없이도 모든 것이 잘 작동했습니다.code(token).

이 문제는 콜백 URL을 인코딩하는 RegisterModel의 OnPostAsync 메서드에 의한 것입니다.

var callbackUrl = Url.Page(
                    "/Account/ConfirmEmail",
                    pageHandler: null,
                    values: new { userId = user.Id, code = code },
                    protocol: Request.Scheme);

await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

이 인코딩(HtmlEncoder 응용 프로그램).체납.Encode()에서 callbackUrl)로 URL '&'가 되어 링크 전체가 무효가 됩니다.

리셋풋의 토큰을 확인할 때도 regex를 사용할 수 있습니다.

var decode = token.Replace(" ", "+");

await _userManager.ResetPasswordAsync(user, decode, Password);

언급URL : https://stackoverflow.com/questions/38781295/asp-net-core-identity-invalid-token-on-confirmation-email

반응형