header, payload, signature로 구성되어 있으며 header는 signature를 해싱하기 위한 알고리즘 정보가 담겨있고 payload는 실제로 사용될 데이터들이 담겨 있습니다.
signature는 토큰의 유효성 검증을 위한 문자열로 이 문자열을 통해 이 토큰이 유효한 토큰인지 검증 가능합니다.
JWT는 인터페이스이고 그 구현체인 JWS, JWE가 존재합니다.
@Data
@ConfigurationProperties(prefix = "jwt")
public class JwtProperties{
private RSAPublicKey accessPublicKey;
private RSAPrivateKey accessPrivateKey;
private Long accessTokenValidityInSeconds;
}
@Configuration
@RequiredArgsConstructor
@EnableConfigurationProperties(JwtProperties.class)
public class JwtConfig{
@Bean(name = "accessJwtDecoder")
public JwtDecoder accessJwtDecoder(JwtProperties jwtProperties) {
return NimbusJwtDecoder.withPublicKey(jwtProperties.getAccessPublicKey()).build();
}
@Bean(name = "accessJwtEncoder")
public JwtEncoder accessJwtEncoder(JwtProperties jwtProperties) {
JWK jwk = new RSAKey.Builder(jwtProperties.getAccessPublicKey())
.privateKey(jwtProperties.getAccessPrivateKey())
.build();
JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
return new NimbusJwtEncoder(jwks);
}
@Bean(name = "accessTokenProvider")
public AccessTokenProvider accessTokenProvider(JwtEncoder accessJwtEncoder,
JwtProperties jwtProperties) {
return new AccessTokenProvider(accessJwtEncoder, jwtProperties.getAccessTokenValidityInSeconds());
}
}
JwtConfig는 JWT 설정 파일로 AccessTokenProvider에 의존성을 주입하고 빈을 생성하는 역할을 수행합니다.
JWT 토큰 인코딩, 디코딩의 책임을 가지는 JwtDecoder 빈, JwtEncoder 빈도 이쪽 설정파일에서 생성합니다.
public final class AccessTokenProvider {
private final JwtEncoder jwtEncoder;
private final long tokenValidityInSeconds;
private static final String AUTHORITIES_KEY = "scp"; // spring security 기본값 (scope)
public AccessTokenProvider(JwtEncoder jwtEncoder, long tokenValidityInSeconds) {
this.jwtEncoder = jwtEncoder;
this.tokenValidityInSeconds = tokenValidityInSeconds;
}
// 토큰 생성
public String createToken(String username, Set<String> authorities) {
String strAuthorities = String.join(" ", authorities);
Instant now = Instant.now();
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(now)
.expiresAt(now.plusSeconds(this.tokenValidityInSeconds))
.subject(username)
.claim(AUTHORITIES_KEY, strAuthorities)
.build();
return jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}
}
TokenProvider를 상속받으며 아이디, 비밀번호를 이용해 토큰을 생성하는 역할을 수행합니다.