SPRING
[Springboot] JWT(6) _ 로그아웃 구현/AccessToken 블랙리스트 + RefreshToken 삭제 + Redis
체제
2022. 8. 24. 00:09
사용자가 로그인 하면, accessToken 과 refreshToken 을 발급하여 응답하였고, 서버에서는 refreshToken 을 사용자 아이디와 함께 Redis 에 저장해 두었다.
사용자가 로그아웃 요청을 하게 되면, accessToken 의 남은 시간을 계산 하여 redis 에 블랙리스트로 저장하였고, refreshToken 은 레디스에서 삭제하였다.
AuthController.java - 로그아웃처리 컨트롤러, 레디스에 저장 및 삭제만 하면 되기때문에 컨트롤러에서 처리하였음
@PostMapping("/logout")
public String userLogout(@RequestBody UserLogoutRequest logoutInfo) throws Exception{
// redis 에서 refresh token 값 삭제
String token = logoutInfo.getAccessToken();
try{
JwtTokenUtil.handleError(token);
}catch(ExpiredJwtException e) {
log.debug("토큰만료");
throw new JwtException("토큰기한이 만료되었습니다.");
}catch(Exception e) {
log.debug("토큰 x");
throw new Exception("올바르지 않은 토큰 입니다.");
}
String id = jwtTokenUtil.getAuth(token);
//redis에서 해당 아이디로 저장된 value 값이 있는지 검사
if(redis.getValues(id) !=null) {
//redis 토큰 삭제
redis.deleteValues(id);
}
Long expiration = jwtTokenUtil.getExpiration(token);
redis.setValues("logout",token, Duration.ofMillis(expiration));
return "success";
}
▶ accessToken 유효기간이나 토큰 형태를 확인 한 후 , 이상이 있다면 예외처리
올바른 값이라면, 아이디(getAuth)를 가지고 redis 에 해당 refreshToken 값이 있는지 검사 후 , 삭제 ( deleteValues )
- JwtTokenUtil.java 의 getExpiration (token) 로 해당 엑세스 토큰의 남은 기간을 확인한 후, redis 에 저장
- → 해당 기간이 지나면 redis 에서 자동으로 삭제
JwtTokenUtil.java
- 토큰 값에서 사용자 아이디 불러오기 : getAuth()
- 엑세스토큰의 남은 유효기간 계산하기 : getExpiration()
public String getAuth(String accessToken) {
Claims claims = Jwts.parserBuilder().setSigningKey(secretKey.getBytes())
.build().parseClaimsJws(accessToken)
.getBody();
return claims.getSubject();
}
public Long getExpiration(String accessToken) {
// accessToken 남은 유효시간
Date expiration = Jwts.parserBuilder().setSigningKey(secretKey.getBytes()
.build().parseClaimsJws(accessToken).getBody().getExpiration();
// 현재 시간
Long now = new Date().getTime();
return (expiration.getTime() - now);
}
RedisService.java - 레디스 값 저장, 불러오기, 삭제 등의 메서드를 정의
@Service
@RequiredArgsConstructor
public class RedisService {
private final RedisTemplate<String, String> redisTemplate;
public void setValues(String key, String data) {
ValueOperations<String, String> values= redisTemplate.opsForValue();
values.set(key,data);
}
public void setValues(String key, String data, Duration duration) {
ValueOperations<String, String> values= redisTemplate.opsForValue();
values.set(key,data,duration);
}
public String getValues(String key) {
ValueOperations<String, String> values= redisTemplate.opsForValue();
return values.get(key);
}
public void deleteValues(String key) {
redisTemplate.delete(key);
}
}
- setValues : key 값으로 data 저장
- setValues + duration : key 값으로 data 를 duration 기간 만큼 저장
- getValues : key 값을 가진 데이터 불러오기
- deleteValues : key 값을 가진 데이터 삭제