728x90
Spring Boot에서 Redis를 이용한 Refresh Token 처리 방법은 다음과 같습니다.
- 의존성 추가
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- Redis 설정
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.database=0
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
- Refresh Token 생성 후 Redis에 저장
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.UUID;
@Component
public class RefreshTokenService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final String PREFIX_REFRESH_TOKEN = "refresh_token:";
// Refresh Token 만료시간 (1주일)
private final Duration REFRESH_TOKEN_EXPIRATION = Duration.ofDays(7);
public String createRefreshToken() {
String refreshToken = PREFIX_REFRESH_TOKEN + UUID.randomUUID().toString();
redisTemplate.opsForValue().set(refreshToken, "", REFRESH_TOKEN_EXPIRATION);
return refreshToken;
}
}
- 1. Access Token 만료 시, Refresh Token을 이용하여 새로운 Access Token을 생성.
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.Date;
@Component
public class AccessTokenService {
@Value("${jwt.secret}")
private String jwtSecret;
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final String PREFIX_REFRESH_TOKEN = "refresh_token:";
// Access Token 만료시간 (1시간)
private final Duration ACCESS_TOKEN_EXPIRATION = Duration.ofHours(1);
public String createAccessToken(String refreshToken) throws Exception {
if (!redisTemplate.hasKey(refreshToken)) {
throw new Exception("Invalid Refresh Token");
}
String subject = ""; // Access Token의 subject
Date now = new Date();
Date expiredAt = new Date(now.getTime() + ACCESS_TOKEN_EXPIRATION.toMillis());
redisTemplate.expire(refreshToken, Duration.ZERO);
String accessToken = Jwts.builder()
.setSubject(subject)
.setIssuedAt(now)
.setExpiration(expiredAt)
.signWith(SignatureAlgorithm.HS256, jwtSecret)
.compact();
return accessToken;
}
}
예시 코드는 Redis에 Refresh Token만 저장하고, Access Token은 JWT로 생성합니다.
이외에도 Redis를 이용하여 Access Token까지 저장할 수 있습니다.
- Redis에 Access Token과 Refresh Token을 저장합니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.UUID;
@Component
public class TokenService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private final String PREFIX_ACCESS_TOKEN = "access_token:";
private final String PREFIX_REFRESH_TOKEN = "refresh_token:";
// Access Token 만료시간 (1시간)
private final Duration ACCESS_TOKEN_EXPIRATION = Duration.ofHours(1);
// Refresh Token 만료시간 (1주일)
private final Duration REFRESH_TOKEN_EXPIRATION = Duration.ofDays(7);
public String createAccessToken() {
String accessToken = PREFIX_ACCESS_TOKEN + UUID.randomUUID().toString();
redisTemplate.opsForValue().set(accessToken, "", ACCESS_TOKEN_EXPIRATION);
return accessToken;
}
public String createRefreshToken() {
String refreshToken = PREFIX_REFRESH_TOKEN + UUID.randomUUID().toString();
redisTemplate.opsForValue().set(refreshToken, "", REFRESH_TOKEN_EXPIRATION);
return refreshToken;
}
public void deleteToken(String accessToken) {
String refreshToken = accessTokenToRefreshToken(accessToken);
redisTemplate.delete(accessToken, refreshToken);
}
public String accessTokenToRefreshToken(String accessToken) {
return accessToken.replace(PREFIX_ACCESS_TOKEN, PREFIX_REFRESH_TOKEN);
}
public boolean isValidRefreshToken(String refreshToken) {
return redisTemplate.hasKey(refreshToken);
}
public boolean isValidAccessToken(String accessToken) {
return redisTemplate.hasKey(accessToken);
}
}
- Access Token의 만료시간을 Redis에서 확인합니다.
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class JwtService {
@Value("${jwt.secret}")
private String jwtSecret;
@Autowired
private TokenService tokenService;
// Access Token 만료시간 (1시간)
private final long ACCESS_TOKEN_EXPIRATION_TIME = 3600000L;
public String createAccessToken() {
String accessToken = tokenService.createAccessToken();
String subject = ""; // Access Token의 subject
Date now = new Date();
Date expiredAt = new Date(now.getTime() + ACCESS_TOKEN_EXPIRATION_TIME);
String refreshToken = tokenService.createRefreshToken();
// Redis에 Access Token과 Refresh Token 저장
RedisTemplate<String, String> redisTemplate = tokenService.getRedisTemplate();
redisTemplate.opsForValue().set(accessToken, refreshToken);
redisTemplate.expire(accessToken, ACCESS_TOKEN_EXPIRATION_TIME);
redisTemplate.opsForValue().set(refreshToken, accessToken);
redisTemplate.expire(refreshToken, tokenService.getREFRESH_TOKEN_EXPIRATION_TIME());
String jwt = Jwts.builder()
.setSubject(subject)
.setIssuedAt(now)
.setExpiration(expiredAt)
.signWith(SignatureAlgorithm.HS256, jwtSecret)
.compact();
return jwt;
}
public String refreshToken(String refreshToken) throws Exception {
if (!tokenService.isValidRefreshToken(refreshToken)) {
throw new Exception("Invalid Refresh Token");
}
String accessToken = tokenService.accessTokenToRefreshToken(refreshToken);
if (!tokenService.isValidAccessToken(accessToken)) {
throw new Exception("Invalid Access Token");
}
// Access Token의 만료시간을 Redis에서 확인
RedisTemplate<String, String> redisTemplate = tokenService.getRedisTemplate();
long expiration = redisTemplate.getExpire(accessToken);
if (expiration < 0) {
throw new Exception("Expired Access Token");
}
String newAccessToken = createAccessToken();
// 기존 Access Token을 삭제하고 새로운 Access Token과 연결된 Refresh Token 저장
redisTemplate.delete(accessToken);
redisTemplate.opsForValue().set(newAccessToken, refreshToken);
redisTemplate.expire(newAccessToken, ACCESS_TOKEN_EXPIRATION_TIME);
redisTemplate.opsForValue().set(refreshToken, newAccessToken);
redisTemplate.expire(refreshToken, tokenService.getREFRESH_TOKEN_EXPIRATION_TIME());
return newAccessToken;
}
}
위의 코드에서는 Redis에 저장된 Access Token의 만료시간을 확인하여 만료된 Access Token인 경우 새로운 Access Token을 생성합니다. 그리고 기존 Access Token을 삭제하고 새로운 Access Token과 연결된 Refresh Token을 Redis에 저장합니다.
위 코드를 참고하여 Redis를 이용하여 Access Token과 Refresh Token을 저장하고, Access Token의 만료시간을 확인하는 코드를 작성해보세요.
내저장소 바로가기 luxury515
'Springboot3.0 > 핵심기능' 카테고리의 다른 글
Spring IoC 에 관하여. (0) | 2023.04.15 |
---|---|
Spring Security 와 Siro 에 대한 비교 (0) | 2023.04.15 |
Redis를 이용한 중복요청 방지 (0) | 2023.04.11 |
Springboot3.0 에서 kafka적용해보기 (0) | 2023.04.11 |
스프링부트 3.0에서 Coffine 라이브러리 설정하기 (0) | 2023.04.11 |