Skip to content

Commit 409516d

Browse files
authored
[Refactor] 토큰, 리이슈, 로그아웃 로직 변경 (#30)
1 parent a47e77c commit 409516d

File tree

7 files changed

+66
-46
lines changed

7 files changed

+66
-46
lines changed

src/main/java/project/backend/business/auth/AuthService.java

+30-23
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.util.Collections;
55
import lombok.RequiredArgsConstructor;
66
import lombok.extern.slf4j.Slf4j;
7-
import org.springframework.security.core.Authentication;
87
import org.springframework.security.core.authority.SimpleGrantedAuthority;
98
import org.springframework.security.core.context.SecurityContextHolder;
109
import org.springframework.stereotype.Service;
@@ -48,26 +47,24 @@ public TokenServiceResponse kakaoLogin(String code) throws JsonProcessingExcepti
4847
@Transactional
4948
public void logout(TokenServiceRequest tokenServiceRequest) {
5049
String accessToken = tokenServiceRequest.getAccessToken();
50+
String refreshToken = tokenServiceRequest.getRefreshToken();
5151

5252
if (accessToken == null || !tokenProvider.validate(accessToken)) {
5353
throw new CustomException(ErrorCode.INVALID_ACCESS_TOKEN);
5454
}
5555

5656
long expiration = tokenProvider.getExpiration(accessToken);
57-
5857
blacklistTokenRedisRepository.save(BlacklistToken.builder()
5958
.token(accessToken)
6059
.expiration(expiration / 1000)
6160
.build());
6261

63-
Authentication authentication = tokenProvider.getAuthentication(accessToken);
64-
String userId = authentication.getName();
65-
66-
refreshTokenRedisRepository.deleteById(userId);
62+
refreshTokenRedisRepository.deleteById(refreshToken);
6763

6864
SecurityContextHolder.clearContext();
6965
}
7066

67+
@Transactional
7168
public TokenServiceResponse reissueAccessToken(TokenServiceRequest tokenServiceRequest) {
7269
String refreshToken = tokenServiceRequest.getRefreshToken();
7370

@@ -76,34 +73,44 @@ public TokenServiceResponse reissueAccessToken(TokenServiceRequest tokenServiceR
7673
throw new CustomException(ErrorCode.INVALID_REFRESH_TOKEN);
7774
}
7875

79-
RefreshToken findToken = refreshTokenRedisRepository.findByRefreshToken(refreshToken);
76+
RefreshToken findToken = refreshTokenRedisRepository.findById(refreshToken)
77+
.orElseThrow(() -> new CustomException(
78+
ErrorCode.NOT_EXIST_REFRESH_TOKEN));
79+
refreshTokenRedisRepository.deleteById(refreshToken);
8080

81+
// 새 AccessToken 생성
8182
TokenServiceResponse tokenServiceResponse = tokenProvider.createToken(
8283
String.valueOf(findToken.getId()),
8384
findToken.getEmail(),
84-
findToken.getAuthority());
85-
86-
refreshTokenRedisRepository.save(RefreshToken.builder()
87-
.id(findToken.getId())
88-
.email(findToken.getEmail())
89-
.authorities(findToken.getAuthorities())
90-
.refreshToken(tokenServiceResponse.getRefreshToken())
91-
.build());
85+
findToken.getAuthority()
86+
);
87+
88+
// 새로 발급된 RefreshToken 을 다시 저장
89+
refreshTokenRedisRepository.save(
90+
RefreshToken.builder()
91+
.id(findToken.getId())
92+
.email(findToken.getEmail())
93+
.authorities(findToken.getAuthorities())
94+
.refreshToken(tokenServiceResponse.getRefreshToken())
95+
.build()
96+
);
9297

9398
SecurityContextHolder.getContext()
9499
.setAuthentication(
95-
tokenProvider.getAuthentication(tokenServiceResponse.getAccessToken()));
100+
tokenProvider.getAuthentication(tokenServiceResponse.getAccessToken())
101+
);
96102

97103
return tokenServiceResponse;
98104
}
99105

100106
private void saveRefreshTokenOnRedis(User user, TokenServiceResponse response) {
101-
refreshTokenRedisRepository.save(RefreshToken.builder()
102-
.id(user.getId())
103-
.email(user.getEmail())
104-
.authorities(Collections.singleton(
105-
new SimpleGrantedAuthority("USER")))
106-
.refreshToken(response.getRefreshToken())
107-
.build());
107+
RefreshToken refreshToken = RefreshToken.builder()
108+
.id(user.getId())
109+
.email(user.getEmail())
110+
.authorities(Collections.singleton(
111+
new SimpleGrantedAuthority("USER")))
112+
.refreshToken(response.getRefreshToken())
113+
.build();
114+
refreshTokenRedisRepository.save(refreshToken);
108115
}
109116
}

src/main/java/project/backend/common/config/RedisConfig.java

+14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
import org.springframework.context.annotation.Configuration;
66
import org.springframework.data.redis.connection.RedisConnectionFactory;
77
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
8+
import org.springframework.data.redis.core.RedisTemplate;
89
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
10+
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
11+
import org.springframework.data.redis.serializer.StringRedisSerializer;
12+
import project.backend.entity.token.RefreshToken;
913

1014
@Configuration
1115
@EnableRedisRepositories
@@ -21,4 +25,14 @@ public class RedisConfig {
2125
public RedisConnectionFactory redisConnectionFactory() {
2226
return new LettuceConnectionFactory(redisHost, redisPort);
2327
}
28+
29+
@Bean
30+
public RedisTemplate<String, RefreshToken> redisTemplate(
31+
RedisConnectionFactory redisConnectionFactory) {
32+
RedisTemplate<String, RefreshToken> template = new RedisTemplate<>();
33+
template.setConnectionFactory(redisConnectionFactory);
34+
template.setKeySerializer(new StringRedisSerializer());
35+
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
36+
return template;
37+
}
2438
}

src/main/java/project/backend/common/error/ErrorCode.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ public enum ErrorCode {
1212
INVALID_REFRESH_TOKEN("유효하지 않은 리프레시 토큰입니다.", HttpStatus.UNAUTHORIZED),
1313
INVALID_ACCESS_TOKEN("유효하지 않은 엑세스 토큰입니다.", HttpStatus.UNAUTHORIZED),
1414
TOKEN_INVALID("유효하지 않은 토큰입니다.", HttpStatus.UNAUTHORIZED),
15-
ACCESS_DENIED("접근 권한이 없습니다.", HttpStatus.FORBIDDEN);
16-
15+
ACCESS_DENIED("접근 권한이 없습니다.", HttpStatus.FORBIDDEN),
16+
NOT_EXIST_REFRESH_TOKEN("존재하지 않는 리프레시 토큰입니다.", HttpStatus.BAD_REQUEST);
1717
private final String message;
1818
private final HttpStatus httpStatus;
1919

Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
package project.backend.entity.token;
22

33
import java.util.Collection;
4-
import org.springframework.data.annotation.Id;
5-
import org.springframework.data.redis.core.RedisHash;
64
import lombok.Builder;
75
import lombok.Getter;
6+
import org.springframework.data.annotation.Id;
7+
import org.springframework.data.redis.core.RedisHash;
88
import org.springframework.security.core.GrantedAuthority;
9+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
910

1011
@Builder
1112
@Getter
12-
@RedisHash(value = "refresh", timeToLive = 604800)
13+
@RedisHash(value = "refreshToken", timeToLive = 86400)
1314
public class RefreshToken {
1415

15-
@Id
16-
private String userId;
17-
1816
private Long id;
19-
private String refreshToken;
2017
private String email;
2118
private Collection<? extends GrantedAuthority> authorities;
2219

20+
@Id
21+
private String refreshToken;
22+
2323
public String getAuthority() {
2424
return authorities.stream()
25-
.map(GrantedAuthority::getAuthority)
26-
.findFirst()
27-
.orElse("");
25+
.map(authority -> new SimpleGrantedAuthority(authority.getAuthority()))
26+
.toList()
27+
.get(0)
28+
.getAuthority();
2829
}
2930
}

src/main/java/project/backend/presentation/auth/util/TokenExtractor.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,28 @@
44

55
import jakarta.servlet.http.HttpServletRequest;
66
import java.util.Optional;
7+
import lombok.extern.slf4j.Slf4j;
78
import org.springframework.beans.factory.annotation.Value;
89
import org.springframework.stereotype.Component;
910
import project.backend.business.auth.request.TokenServiceRequest;
1011

12+
@Slf4j
1113
@Component
1214
public class TokenExtractor {
1315

1416
@Value("${jwt.access_header}")
1517
private String accessTokenHeader;
16-
18+
1719
@Value("${jwt.refresh_header}")
1820
private String refreshTokenHeader;
1921

2022
public TokenServiceRequest extractTokenRequest(HttpServletRequest request) {
23+
String accessToken = extractAccessToken(request).orElse(null);
24+
String refreshToken = extractRefreshToken(request).orElse(null);
25+
log.info("Logout initiated with accessToken: {}, refreshToken: {}", accessToken, refreshToken);
2126
return TokenServiceRequest.builder()
22-
.accessToken(extractAccessToken(request).orElse(null))
23-
.refreshToken(extractRefreshToken(request).orElse(null))
27+
.accessToken(accessToken)
28+
.refreshToken(refreshToken)
2429
.build();
2530
}
2631

src/main/java/project/backend/repository/auth/BlacklistTokenRedisRepository.java

-1
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,4 @@
44
import project.backend.entity.token.BlacklistToken;
55

66
public interface BlacklistTokenRedisRepository extends CrudRepository<BlacklistToken, String> {
7-
87
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
package project.backend.repository.auth;
22

3-
import org.springframework.data.redis.core.RedisHash;
43
import org.springframework.data.repository.CrudRepository;
54
import project.backend.entity.token.RefreshToken;
65

7-
@RedisHash
8-
public interface RefreshTokenRedisRepository extends CrudRepository<RefreshToken, Long> {
9-
10-
RefreshToken findByRefreshToken(String refreshToken);
11-
12-
void deleteById(String userId);
6+
public interface RefreshTokenRedisRepository extends CrudRepository<RefreshToken, String> {
137
}

0 commit comments

Comments
 (0)