데브코스 W11D3

코끼릭·2022년 6월 1일
0

TIL

목록 보기
35/36

JWT (Json Web Token)

Session을 사용하는 방식의 경우 Stateful한 상태이기 때문에 수평확장에 어려움이 가지고 있어 이를 대신하여 Rest API에서 Stateless 상태를 유지하고 서버에서 사용자를 인증할 수 있는 JSON 포맷을 사용한 인증수단이다. JWT는 Header, Payload, Signature 세 부분으로 구성되어 있고 실제 JWT를 전달할 때는 Base64 Url-Safe 방식으로 인코딩을 하여 전달한다.

  • Header : JWT를 검증하는데 필요한 정보인 토큰 타입, 사용된 알고리즘 정보를 담고 있다.
  • Payload : JWT를 통해 전달하고자 하는 데이터가 담긴 부분으로 Claim-Set 이라고 하며 민감정보를 포함하지 않아야 한다.
  • Signature : 토큰이 위변조 되지 않았음을 증명하는 토큰 생성 주체만 알고있는 비밀키를 이용하여 서명된 값이다.

JWT 동작 과정

  1. 서버에서 사용자가 성공적으로 인증되면 JWT를 반환한다.
  2. 클라이언트를 JWT를 저장하고 이후 서버에 요청을 보낼 때 HTTP 헤더에 해당 JWT를 함께 보낸다.
  3. 서버는 클라이언트가 전달한 JWT의 서명을 확인하여 사용자를 식별한다.

JWT 장점과 단점

  • 장점
    • 사용자 인증에 필요한 모든 정보는 토큰 자체에 포함하기 때문에 따로 스토리지가 필요 없음
    • 따라서, Active User가 많은 서비스에서 JWT사용이 유리함
  • 단점
    • 토큰 크기를 가능한 작게 유지해야 함
    • 유효기간이 남아 있는 정상적인 토큰에 대해 강제적으로 만료 처리가 어려움

JWT 사용 예제

  1. yml 파일에서 JWT 토큰 설정을 가져오는 빈을 설정한다.

    @Component
    @ConfigurationProperties(prefix = "jwt")
    public class JwtConfigure {
    
      private String header;
    
      private String issuer;
    
      private String clientSecret;
    
      private int expirySeconds;
    
      public String getHeader() {
        return header;
      }
    
      public void setHeader(String header) {
        this.header = header;
      }
    
      public String getIssuer() {
        return issuer;
      }
    
      public void setIssuer(String issuer) {
        this.issuer = issuer;
      }
    
      public String getClientSecret() {
        return clientSecret;
      }
    
      public void setClientSecret(String clientSecret) {
        this.clientSecret = clientSecret;
      }
    
      public int getExpirySeconds() {
        return expirySeconds;
      }
    
      public void setExpirySeconds(int expirySeconds) {
        this.expirySeconds = expirySeconds;
      }
    
    }
  2. JWT 토큰설정을 참고하여 JWT 객체를 생성하는 빈을 설정한다.

    @Bean
    public Jwt jwt(JwtConfigure jwtConfigure) {
    return new Jwt(
      jwtConfigure.getIssuer(),
      jwtConfigure.getClientSecret(),
      jwtConfigure.getExpirySeconds()
    );
    }
  3. JWT 발행을 위한 sign 메소드와 JWT 검증을 위한 verify 메소드를 작성한다.

    public final class Jwt {
    
      private final String issuer;
    
      private final String clientSecret;
    
      private final int expirySeconds;
    
      private final Algorithm algorithm;
    
      private final JWTVerifier jwtVerifier;
    
      public Jwt(String issuer, String clientSecret, int expirySeconds) {
        this.issuer = issuer;
        this.clientSecret = clientSecret;
        this.expirySeconds = expirySeconds;
        this.algorithm = Algorithm.HMAC512(clientSecret);
        this.jwtVerifier = com.auth0.jwt.JWT.require(algorithm)
          .withIssuer(issuer)
          .build();
      }
    
        public String sign(Claims claims) {
        Date now = new Date();
        JWTCreator.Builder builder = com.auth0.jwt.JWT.create();
        builder.withIssuer(issuer);
        builder.withIssuedAt(now);
        if (expirySeconds > 0) {
          builder.withExpiresAt(new Date(now.getTime() + expirySeconds * 1_000L));
        }
        builder.withClaim("username", claims.username);
        builder.withArrayClaim("roles", claims.roles);
        return builder.sign(algorithm);
      }
    
      public Claims verify(String token) throws JWTVerificationException {
        return new Claims(jwtVerifier.verify(token));
      }
    
      // ... 생략 ...
    
        static public class Claims {/*생략*/}
    }
profile
ㅇㅅㅇ

0개의 댓글