Skip to content

Commit abaaca0

Browse files
authored
fix: application-prod.yml에서 쿠키를 쓸지 말지 결정할 수 있게 수정 (#69)
* fix: application-prod.yml에서 쿠키를 쓸지 말지 결정할 수 있게 수정 * test: 테스트 코드 작성
1 parent a052e1e commit abaaca0

File tree

11 files changed

+621
-392
lines changed

11 files changed

+621
-392
lines changed

src/main/java/sevenstar/marineleisure/global/config/SecurityConfig.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Arrays;
44

5+
import org.springframework.beans.factory.annotation.Value;
56
import org.springframework.context.annotation.Bean;
67
import org.springframework.context.annotation.Configuration;
78
import org.springframework.http.HttpMethod;
@@ -28,6 +29,9 @@ public class SecurityConfig {
2829
private final JwtTokenProvider jwtTokenProvider;
2930
private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
3031

32+
@Value("${jwt.use-cookie:true}")
33+
private boolean useCookie;
34+
3135
@Bean
3236
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
3337
http
@@ -75,7 +79,10 @@ public CorsConfigurationSource corsConfigurationSource() {
7579

7680
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
7781
config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "X-Requested-With"));
78-
config.setAllowCredentials(true);
82+
83+
// jwt.use-cookie 설정에 따라 credentials 설정 변경
84+
// useCookie=true 일 때만 allowCredentials=true (쿠키 사용)
85+
config.setAllowCredentials(useCookie);
7986
config.setMaxAge(3600L); // 프리플라이트 요청 캐싱 (1시간)
8087

8188
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
Lines changed: 101 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,114 @@
11
package sevenstar.marineleisure.global.util;
22

3+
import java.time.Duration;
4+
5+
import org.springframework.beans.factory.annotation.Value;
6+
import org.springframework.stereotype.Component;
7+
38
import jakarta.servlet.http.Cookie;
49
import jakarta.servlet.http.HttpServletRequest;
510
import jakarta.servlet.http.HttpServletResponse;
611

7-
import org.springframework.stereotype.Component;
8-
912
/**
1013
* 쿠키 관리 유틸리티
1114
* 쿠키 생성, 조회, 삭제 로직을 담당합니다.
15+
* jwt.use-cookie 설정에 따라 쿠키 설정을 다르게 적용합니다.
1216
*/
1317
@Component
1418
public class CookieUtil {
1519

16-
/**
17-
* 리프레시 토큰 쿠키 생성
18-
*
19-
* @param refreshToken 리프레시 토큰
20-
* @return 생성된 쿠키
21-
*/
22-
public Cookie createRefreshTokenCookie(String refreshToken) {
23-
Cookie refreshTokenCookie = new Cookie("refresh_token", refreshToken);
24-
refreshTokenCookie.setHttpOnly(true);
25-
refreshTokenCookie.setSecure(true);
26-
refreshTokenCookie.setPath("/");
27-
refreshTokenCookie.setMaxAge((int)(14 * 24 * 60 * 60)); // 14일
28-
refreshTokenCookie.setAttribute("SameSite", "None");
29-
return refreshTokenCookie;
30-
}
31-
32-
/**
33-
* 리프레시 토큰 쿠키 삭제
34-
*
35-
* @return 삭제용 쿠키
36-
*/
37-
public Cookie deleteRefreshTokenCookie() {
38-
Cookie refreshTokenCookie = new Cookie("refresh_token", "");
39-
refreshTokenCookie.setHttpOnly(true);
40-
refreshTokenCookie.setSecure(true);
41-
refreshTokenCookie.setPath("/");
42-
refreshTokenCookie.setMaxAge(0); // 쿠키 즉시 만료
43-
refreshTokenCookie.setAttribute("SameSite", "None");
44-
return refreshTokenCookie;
45-
}
46-
47-
/**
48-
* 쿠키 조회
49-
*
50-
* @param request HTTP 요청
51-
* @param name 쿠키 이름
52-
* @return 찾은 쿠키 또는 null
53-
*/
54-
public Cookie getCookie(HttpServletRequest request, String name) {
55-
Cookie[] cookies = request.getCookies();
56-
if (cookies != null) {
57-
for (Cookie cookie : cookies) {
58-
if (cookie.getName().equals(name)) {
59-
return cookie;
60-
}
61-
}
62-
}
63-
return null;
64-
}
65-
66-
/**
67-
* 쿠키 추가
68-
*
69-
* @param response HTTP 응답
70-
* @param cookie 추가할 쿠키
71-
*/
72-
public void addCookie(HttpServletResponse response, Cookie cookie) {
73-
response.addCookie(cookie);
74-
}
75-
}
20+
@Value("${jwt.use-cookie:true}")
21+
private boolean useCookie;
22+
23+
/**
24+
* 리프레시 토큰 쿠키 생성
25+
* jwt.use-cookie 설정에 따라 쿠키 설정이 달라집니다.
26+
* - useCookie=false: secure=false, sameSite=Lax
27+
* - useCookie=true: secure=true, sameSite=None
28+
*
29+
* @param refreshToken 리프레시 토큰
30+
* @return 생성된 쿠키
31+
*/
32+
public Cookie createRefreshTokenCookie(String refreshToken) {
33+
boolean useSecureCookie = useCookie;
34+
35+
// Create a standard Cookie
36+
Cookie cookie = new Cookie("refresh_token", refreshToken);
37+
cookie.setHttpOnly(true);
38+
cookie.setSecure(useSecureCookie);
39+
cookie.setPath("/");
40+
cookie.setMaxAge((int) Duration.ofDays(14).toSeconds());
41+
42+
// Set SameSite attribute
43+
if (useSecureCookie) {
44+
cookie.setAttribute("SameSite", "None");
45+
} else {
46+
cookie.setAttribute("SameSite", "Lax");
47+
}
48+
49+
return cookie;
50+
}
51+
52+
/**
53+
* 리프레시 토큰 쿠키 삭제
54+
* jwt.use-cookie 설정에 따라 쿠키 설정이 달라집니다.
55+
*
56+
* @return 삭제용 쿠키
57+
*/
58+
public Cookie deleteRefreshTokenCookie() {
59+
boolean useSecureCookie = useCookie;
60+
61+
Cookie cookie = new Cookie("refresh_token", "");
62+
cookie.setHttpOnly(true);
63+
cookie.setSecure(useSecureCookie);
64+
cookie.setPath("/");
65+
cookie.setMaxAge(0); // 쿠키 즉시 만료
66+
67+
// Set SameSite attribute
68+
if (useSecureCookie) {
69+
cookie.setAttribute("SameSite", "None");
70+
} else {
71+
cookie.setAttribute("SameSite", "Lax");
72+
}
73+
74+
return cookie;
75+
}
76+
77+
/**
78+
* 쿠키 조회
79+
*
80+
* @param request HTTP 요청
81+
* @param name 쿠키 이름
82+
* @return 찾은 쿠키 또는 null
83+
*/
84+
public Cookie getCookie(HttpServletRequest request, String name) {
85+
Cookie[] cookies = request.getCookies();
86+
if (cookies != null) {
87+
for (Cookie cookie : cookies) {
88+
if (cookie.getName().equals(name)) {
89+
return cookie;
90+
}
91+
}
92+
}
93+
return null;
94+
}
95+
96+
/**
97+
* 쿠키 추가
98+
*
99+
* @param response HTTP 응답
100+
* @param cookie 추가할 쿠키
101+
*/
102+
public void addCookie(HttpServletResponse response, Cookie cookie) {
103+
response.addCookie(cookie);
104+
}
105+
106+
/**
107+
* 현재 설정이 쿠키를 사용하는지 여부 반환
108+
*
109+
* @return jwt.use-cookie 설정값
110+
*/
111+
public boolean isUsingCookie() {
112+
return useCookie;
113+
}
114+
}

src/main/java/sevenstar/marineleisure/member/controller/AuthController.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,25 +102,35 @@ public ResponseEntity<BaseResponse<LoginResponse>> kakaoLogin(
102102
/**
103103
* 토큰 재발급
104104
*
105-
* @param refreshToken 리프레시 토큰 (쿠키에서 추출)
105+
* @param refreshToken 리프레시 토큰 (쿠키 또는 요청 본문에서 추출)
106+
* @param refreshTokenFromBody 요청 본문에서 전달된 리프레시 토큰 (jwt.use-cookie=false 설정용)
106107
* @param response HTTP 응답
107108
* @return 새로운 액세스 토큰과 사용자 정보
108109
*/
109110
@PostMapping("/refresh")
110111
public ResponseEntity<BaseResponse<LoginResponse>> refreshToken(
111-
@CookieValue("refresh_token") String refreshToken,
112+
@CookieValue(value = "refresh_token", required = false) String refreshToken,
113+
@RequestBody(required = false) Map<String, String> refreshTokenFromBody,
112114
HttpServletResponse response
113115
) {
114-
log.info("Refreshing token with refresh token: {}", refreshToken);
116+
log.info("Refreshing token");
115117

116118
try {
119+
String token = refreshToken;
120+
121+
// jwt.use-cookie=false 설정일 때는 요청 본문에서 리프레시 토큰 추출
122+
if ((token == null || token.isEmpty()) && refreshTokenFromBody != null) {
123+
token = refreshTokenFromBody.get("refreshToken");
124+
log.info("Using refresh token from request body: {}", token);
125+
}
126+
117127
// 리프레시 토큰이 없는 경우
118-
if (refreshToken == null || refreshToken.isEmpty()) {
128+
if (token == null || token.isEmpty()) {
119129
log.error("Empty refresh token");
120130
return BaseResponse.error(MemberErrorCode.REFRESH_TOKEN_MISSING);
121131
}
122132

123-
LoginResponse loginResponse = authService.refreshToken(refreshToken, response);
133+
LoginResponse loginResponse = authService.refreshToken(token, response);
124134
return BaseResponse.success(loginResponse);
125135
} catch (IllegalArgumentException e) {
126136
log.info("Invalid refresh token: {}", e.getMessage());
Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,73 @@
11
package sevenstar.marineleisure.member.dto;
22

33
import lombok.Builder;
4+
import sevenstar.marineleisure.member.domain.Member;
45

56
/**
67
* 로그인 성공 시 반환되는 DTO
78
* Access 토큰과 사용자 정보를 포함
8-
* Refresh 토큰은 쿠키로 전송
9+
* Refresh 토큰은 jwt.use-cookie 설정에 따라 쿠키 또는 응답 본문으로 전송
910
* @param accessToken
1011
* @param userId
1112
* @param email
1213
* @param nickname
14+
* @param refreshToken jwt.use-cookie=false 설정일 때만 사용 (쿠키 대신 응답 본문에 포함)
1315
*/
1416
@Builder
1517
public record LoginResponse(
1618
String accessToken,
1719
Long userId,
1820
String email,
19-
String nickname
21+
String nickname,
22+
String refreshToken
2023
) {
24+
/**
25+
* 쿠키 방식 사용 시 (jwt.use-cookie=true) 생성자
26+
*/
27+
public static LoginResponse of(String accessToken, Long userId, String email, String nickname) {
28+
return LoginResponse.builder()
29+
.accessToken(accessToken)
30+
.userId(userId)
31+
.email(email)
32+
.nickname(nickname)
33+
.build();
34+
}
35+
36+
/**
37+
* JSON 응답 방식 사용 시 (jwt.use-cookie=false) 생성자
38+
*/
39+
public static LoginResponse of(String accessToken, Long userId, String email, String nickname, String refreshToken) {
40+
return LoginResponse.builder()
41+
.accessToken(accessToken)
42+
.userId(userId)
43+
.email(email)
44+
.nickname(nickname)
45+
.refreshToken(refreshToken)
46+
.build();
47+
}
48+
49+
/**
50+
* 사용자 정보와 액세스 토큰만으로 생성하는 편의 메서드
51+
*/
52+
public static LoginResponse of(String accessToken, Member member) {
53+
return LoginResponse.builder()
54+
.accessToken(accessToken)
55+
.userId(member.getId())
56+
.email(member.getEmail())
57+
.nickname(member.getNickname())
58+
.build();
59+
}
60+
61+
/**
62+
* 사용자 정보와 액세스 토큰, 리프레시 토큰으로 생성하는 편의 메서드 (jwt.use-cookie=false 설정용)
63+
*/
64+
public static LoginResponse of(String accessToken, Member member, String refreshToken) {
65+
return LoginResponse.builder()
66+
.accessToken(accessToken)
67+
.userId(member.getId())
68+
.email(member.getEmail())
69+
.nickname(member.getNickname())
70+
.refreshToken(refreshToken)
71+
.build();
72+
}
2173
}

0 commit comments

Comments
 (0)