▶ jwt.TokenProvider 클래스
더보기
@Slf4j
@Component
public class TokenProvider implements InitializingBean {
private static final String AUTHORITIES_KEY = "auth";
private final String secret;
private final long accessTokenValidityInMilliseconds;
private final long refreshTokenValidityInMilliseconds;
private Key key;
@Autowired
private RefreshTokenRepository refreshTokenRepository;
...
}
▷ jwt.TokenProvider 클래스 분석
@Slf4j
@Component
public class TokenProvider implements InitializingBean {
- @Slf4j: 이 어노테이션은 Lombok에서 제공하는 기능으로, log라는 이름의 Logger 객체를 자동으로 생성한다. 이를 통해 log.info(), log.debug(), log.error()와 같은 로그 메소드를 쉽게 사용할 수 있다. 로그를 남길 수 있는 기능을 추가해주는 역할이다.
- @Component: 이 어노테이션은 Spring에 이 클래스를 Bean으로 등록하도록 알려준다. Spring은 이 클래스를 자동으로 스캔하고 애플리케이션의 다른 부분에서 의존성 주입을 통해 사용할 수 있게 된다.
- public class TokenProvider implements InitializingBean: InitializingBean 인터페이스를 구현하여 Bean의 초기화 후 작업을 정의할 수 있다.
private static final String AUTHORITIES_KEY = "auth";
private final String secret;
private final long accessTokenValidityInMilliseconds;
private final long refreshTokenValidityInMilliseconds;
private Key key;
@Autowired
private RefreshTokenRepository refreshTokenRepository;
- private static final String AUTHORITIES_KEY = "auth";: JWT에 저장할 권한 정보의 키다.
- private final String secret;: JWT 서명에 사용되는 비밀 키다.
- private final long accessTokenValidityInMilliseconds;: 액세스 토큰의 유효 시간을 밀리초 단위로 저장한다.
- private final long refreshTokenValidityInMilliseconds;: 리프레시 토큰의 유효 시간을 밀리초 단위로 저장 한 다.
- private Key key;: JWT 서명에 사용할 키를 저장 한다.
- @Autowired private RefreshTokenRepository refreshTokenRepository;: 리프레시 토큰을 데이터베이스에 저장하는 리포지토리다.
▶ TokenProvider 생성자
public TokenProvider(
@Value("${jwt.secret}") String secret,
@Value("${jwt.token-validity-in-seconds}") long accessTokenValidityInSeconds,
@Value("${jwt.refreshtoken-validity-in-seconds}") long refreshTokenValidityInSeconds) {
this.secret = secret;
this.accessTokenValidityInMilliseconds = accessTokenValidityInSeconds * 1000;
this.refreshTokenValidityInMilliseconds = refreshTokenValidityInSeconds * 1000;
}
- public TokenProvider(...): 생성자에서 @Value 어노테이션을 사용하여 application.properties 또는 application.yml 파일에 정의된 JWT 관련 설정 값을 주입받는다.
- this.secret = secret;: 비밀 키를 초기화한다.
- this.accessTokenValidityInMilliseconds = accessTokenValidityInSeconds * 1000;: 액세스 토큰의 유효 시간을 밀리초로 변환한다.
- this.refreshTokenValidityInMilliseconds = refreshTokenValidityInSeconds * 1000;: 리프레시 토큰의 유효 시간을 밀리초로 변환한다.
▶ afterPropertiesSet 클래스
@Override
public void afterPropertiesSet() {
byte[] keyBytes = Decoders.BASE64.decode(secret);
this.key = Keys.hmacShaKeyFor(keyBytes);
}
- @Override public void afterPropertiesSet(): Spring에서 Bean이 생성되고 모든 속성이 주입된 후 호출되는 메소드다.
- byte[] keyBytes = Decoders.BASE64.decode(secret);: Base64로 인코딩된 비밀 키를 디코드한다.
- this.key = Keys.hmacShaKeyFor(keyBytes);: 디코드된 키를 사용하여 HMAC SHA 알고리즘에 사용할 키를 생성한다.
▶ createToken 클래스
public String createToken(Authentication authentication, boolean isAccessToken) {
String authorities = authentication.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
long now = (new Date()).getTime();
long date = 0;
if (isAccessToken)
date = now + this.accessTokenValidityInMilliseconds;
else
date = now + this.refreshTokenValidityInMilliseconds;
Date validity = new Date(date);
return Jwts.builder()
.setSubject(authentication.getName())
.claim(AUTHORITIES_KEY, authorities)
.signWith(key, SignatureAlgorithm.HS512)
.setExpiration(validity)
.compact();
}
- public String createToken(...): JWT를 생성하는 메소드다.
- String authorities = ...: 인증 객체에서 권한 정보를 가져와서 쉼표로 구분된 문자열로 만다.
- long now = (new Date()).getTime();: 현재 시간을 밀리초로 가져온다.
- long date = 0; ...: 액세스 토큰과 리프레시 토큰의 유효 시간을 설정한다.
- Date validity = new Date(date);: 유효한 종료 시간을 나타내는 Date 객체를 생성한다.
- return Jwts.builder()...compact();: JWT를 생성하고 반환한다.
- setSubject(...): JWT의 주체(이 경우 사용자의 이름)를 설정한다.
- claim(...): JWT에 권한 정보를 추가한다.
- signWith(...): HMAC SHA-512 알고리즘과 키를 사용하여 서명한다.
- setExpiration(...): JWT의 만료 시간을 설정한다.
▶ createAndPersistRefreshTokenForUser 메서드
public String createAndPersistRefreshTokenForUser(Authentication authentication) {
String refreshToken = this.createToken(authentication, false);
long now = (new Date()).getTime();
Date validity = new Date(now + this.refreshTokenValidityInMilliseconds);
LocalDateTime localDateTime = validity.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
String username = authentication.getName();
RefreshToken refreshTokenEntity = new RefreshToken();
refreshTokenEntity.setUsername(username);
refreshTokenEntity.setToken(refreshToken);
refreshTokenEntity.setExpiryDate(localDateTime);
refreshTokenRepository.save(refreshTokenEntity);
return refreshToken;
}
- public String createAndPersistRefreshTokenForUser(...): 사용자에 대한 리프레시 토큰을 생성하고 저장하는 메소드다.
- String refreshToken = this.createToken(authentication, false);: 리프레시 토큰을 생성한다.
- LocalDateTime localDateTime = validity.toInstant()...;: 유효 시간을 LocalDateTime으로 변환한다.
- RefreshToken refreshTokenEntity = new RefreshToken();: 리프레시 토큰을 저장할 엔티티 객체를 생성한다.
- refreshTokenRepository.save(refreshTokenEntity);: 리프레시 토큰을 데이터베이스에 저장한다.
▶ getAuthentication 메서드
public Authentication getAuthentication(String token) {
Claims claims = Jwts
.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(token)
.getBody();
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
User principal = new User(claims.getSubject(), "", authorities);
return new UsernamePasswordAuthenticationToken(principal, token, authorities);
}
- public Authentication getAuthentication(...): JWT에서 인증 정보를 추출하고 Authentication 객체를 반환하는 메소드다.
- Claims claims = Jwts.parserBuilder()...parseClaimsJws(token).getBody();: JWT를 파싱하여 클레임을 가져온다.
- Collection<? extends GrantedAuthority> authorities = ...;: 권한 정보를 가져와 GrantedAuthority 객체로 변환한다.
- User principal = new User(...);: JWT의 주체를 기반으로 사용자 객체를 생성한다.
- return new UsernamePasswordAuthenticationToken(...);: 사용자 정보를 담은 Authentication 객체를 반환한다.
▶ validateToken 메서드
public boolean validateToken(String token) {
try {
Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token);
return true;
} catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
log.info("잘못된 JWT 서명입니다.");
} catch (ExpiredJwtException e) {
log.info("만료된 JWT 토큰입니다.");
} catch (UnsupportedJwtException e) {
log.info("지원되지 않는 JWT 토큰입니다.");
} catch (IllegalArgumentException e) {
log.info("JWT 토큰이 잘못되었습니다.");
}
return false;
}
- try 블록에서 Jwts.parserBuilder()를 호출하여 JWT 파서 객체를 생성한다.
- setSigningKey(key): 메서드를 통해 토큰을 검증할 때 사용할 서명 키를 설정한다. 이 키는 JWT를 생성할 때 사용된 것과 동일해야 한다.
- parseClaimsJws(token): 주어진 JWT 토큰을 파싱하고 검증한다. 만약 검증이 성공하면 해당 메서드는 토큰의 클레임을 반환한다.
- io.jsonwebtoken.security.SecurityException | MalformedJwtException e: JWT 서명이 잘못되었거나 JWT 형식이 올바르지 않을 경우 발생하는 예외를 처리한다.
- ExpiredJwtException e: JWT가 만료되었을 때 발생하는 예외를 처리한다.
- IllegalArgumentException e: JWT 토큰이 null이거나 비어 있는 경우 발생하는 예외를 처리한다.
- return false;: 모든 예외 처리 후, 토큰이 유효하지 않다는 것을 의미하는 false를 반환한다.
'개인 코드 분석' 카테고리의 다른 글
스프링 시큐리티 Jwt: jwt.SecurityConfig (0) | 2024.11.05 |
---|---|
스프링 시큐리티 Jwt: jwt.JwtSecurityConfig (0) | 2024.11.05 |
스프링 시큐리티 Jwt: jwt.JwtFilter (0) | 2024.11.05 |
스프링 시큐리티 Jwt: jwt.JwtAuthenticationEntryPoint (0) | 2024.11.05 |
스프링 시큐리티 Jwt: jwt.JwtAccessDeniedHandler (0) | 2024.11.05 |