ASP.NET Core의 JWT 토큰 클레임

https://eduardstefanescu.dev/2020/05/02/jwt-token-claims-in-asp-dotnet-core/에 원래 게시되었습니다.


대칭 및 비대칭 키를 사용하는 이전 두 문서에서 인증을 제시한 후 이 문서에서는 인증, 훨씬 더 정확히는 클레임 ​​및 역할에 대해 설명합니다. 첫 번째 부분에서는 JWT 클레임의 핵심 개념을 소개하고 두 번째 부분에서는 실제 구현에 대해 설명합니다.

대칭 키를 사용한 JWT 인증: https://stefanescueduard.github.io/2020/04/11/jwt-authentication-with-symmetric-encryption-in-asp-dotnet-core/ .\
비대칭 키를 사용한 JWT 인증: https://stefanescueduard.github.io/2020/04/25/jwt-authentication-with-asymmetric-encryption-in-asp-dotnet-core/ .

소개

Claims in JWT Token are used to store key data (e.g. username, timezone, or roles) in the Token payload, besides the IssuedAt (i.e. iat), which is added by default.\
In .NET Core, Claims can be used without installing any additional package, it comes from the  System.Security.Claims  package. From this package, in this article, just the  Claim  and  ClaimTypes  will be used. You can find more about them here: 
https://docs.microsoft.com/en-us/dotnet/api/system.security.claims?view=netcore-3.1 .\
이 문서에서는 이전 문서의 JwtAuthentication.AsymmetricEncryption 프로젝트를 사용하고 클레임 및 역할을 지원하는 몇 가지 기능을 추가하기로 했습니다. 따라서 이전 두 기사를 읽고 있다면 이 기사에서 작은 변경 사항을 볼 수 있습니다.

추가 변경 사항

As I said there will be some minor changes, to support the Claims and Roles feature. These changes are not required in your type of scenario but are required for a better understanding of this article. So if your target is to find the actual implementation, you can skip the  AuthenticationService  class.

인증 서비스

The  AuthenticationService  now will have an additional  UserRepository  from which the data about the  User  will be retrieved. And the  TokenService  will receive the  User  to generate the  securityToken .

public string Authenticate(UserCredentials userCredentials)
{
    userService.ValidateCredentials(userCredentials);
    User user = userRepository.GetUser(userCredentials.Username);
    var tokenService = new TokenService(user);
    string securityToken = tokenService.GetToken();

    return securityToken;
}

Authenticate  method was explained in the previous two articles and all the code can be found on my GitHub account, there will be a link to it at the end of this article.\
UserRepository  contains a predefined list of users, and the  GetUser  method returns only the  User  with the given username, this logic was on the  UserService .

사용자

User  now contains the  Roles  property and the  Claims  method which will build the claims with the  Username  and  Roles . For the sake of this article, we're supposing that the  Roles  will be all the time set, so we'll don't need to worry if this collection will be  null .

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
    public IEnumerable<string> Roles { get; set; }

    public IEnumerable<Claim> Claims()
    {
        var claims = new List<Claim> { new Claim(ClaimTypes.Name, Username) };
        claims.AddRange(Roles.Select(role => new Claim(ClaimTypes.Role, role)));

        return claims;
    }
}
You may notice that there are some predefined  ClaimTypes , created by a standard (i.e.  http://docs.oasis-open.org/imi/ns/identity-200810 ), 그러나 일반 텍스트만 있습니다. 따라서 ClaimTypes도 원하는 대로 맞춤설정할 수 있습니다.\ClaimsTokenService에서 실제로 토큰 페이로드인 주제를 설정하는 데 사용됩니다.

토큰 서비스

TokenService  is receiving the  User  from the  AuthenticationService  and uses it to set the Subject (i.e. Payload) of the Token.\
Besides this change, there is only one change that has to be done, on the  GetTokenDescriptor  method, when the  SecurityTokenDescriptor  is created, the subject is initialized with a new  ClaimsIdentity  that gets the user claims.

private SecurityTokenDescriptor GetTokenDescriptor()
{
    var tokenDescriptor = new SecurityTokenDescriptor
    {
        Subject = new ClaimsIdentity(user.Claims()),
        ...
    };

    return tokenDescriptor;
}

사용자 컨트롤러

Now that the Claims are set, the  UserController  will be the playground for the set claims and roles. In order to accept requests with the created Token, the Controller must have the same Scheme as the Token set on the  AuthorizeAttribute .

[Route("identity/[controller]")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class UserController : ControllerBase
{
    ...
}

GetClaims 메서드

Firstly the user claims will be getting by using the  User  from the base class of the controller (i.e.  ControllerBase ), which has the  Claims  getter. Because the  Claim  class has many properties, that can be found on the Microsoft website:  https://docs.microsoft.com/en-us/dotnet/api/system.security.claims.claim?view=netcore-3.1 이 예에서는 TypeValue 가 사용됩니다.

{"lastUpload":"2020-06-03T07:43:38.634Z","extensionVersion":"v3.4.3"}


아래 그림에서 john.doe 사용자의 주장은 get입니다. namerole 클레임 외에 명시적으로 추가되지 않은 세 가지가 더 있음을 알 수 있습니다. 그러나 토큰이 생성될 때 기본적으로 추가되었습니다.


  • nbf 또는 Not Before는 토큰이 생성된 후에만 유효하고 과거에는 유효하지 않음을 확인하는 데 사용됩니다.
  • exp 또는 만료 시간은 설명이 필요 없으며 토큰이 생성될 때 LifeTimeValidator가 지정되었기 때문에 설정되었습니다.
  • iat 또는 이전에 언급한 발행일은 토큰이 생성된 시간입니다.\
    시간은 Unix epoch 시간의 초를 나타냅니다.

  • 모든 주장은 다음 기사의 참고 자료로 사용한 이 과학 논문에서 찾을 수 있습니다. https://tools.ietf.org/html/rfc7519#section-4.1 .

    GetName

    In the  GetName  method, the value of  Name  claim is get for the given Token, which represents the username. The  User  already has predefined methods, like  FindFirstValue  in order to expose its property easily.

    [HttpGet("name")]
    public IActionResult GetName()
    {
        string name = User.FindFirstValue(ClaimTypes.Name);
        return Ok(name);
    }
    

    In the response, only the username is returned from the Claim.



    GetRoles

    And the last method is using the  AuthorizedAttribute  with the  Roles  property to give access only to the users that have the set role, in this case, Admin.

    [HttpGet("roles")]
    [Authorize(Roles = "Admin")]
    public IActionResult GetRoles()
    {
        IEnumerable<Claim> roleClaims = User.FindAll(ClaimTypes.Role);
        IEnumerable<string> roles = roleClaims.Select(r => r.Value);
        return Ok(roles);
    }
    

    Let's test with john.doe user, that only have the User role.



    요청이 AuthorizeAttribute`를 전달하지 않았기 때문에 응답 코드는 403 Forbidden입니다.

    이제 jane.doe 사용자가 로그인하고 생성된 토큰으로 그녀의 역할을 가져오려고 합니다.



    위의 그림에서 응답 코드는 정상이고 본문에는 사용자 역할이 포함되어 있습니다. 역할이 요청된 역할이기 때문입니다.


    이 기사의 소스 코드는 내 GitHub 계정https://github.com/StefanescuEduard/JwtAuthentication에서 찾을 수 있습니다.

    이 기사를 읽어 주셔서 감사합니다. 흥미로웠다면 동료 및 친구들과 공유하십시오. 또는 개선할 수 있는 부분이 있으면 알려주세요.

    좋은 웹페이지 즐겨찾기