Skip to content

Commit

Permalink
refactor : MemberController 개선 및 CookieExtractor 제거
Browse files Browse the repository at this point in the history
- `CookieExtractor` 대신 `@CookieValue` 이용
- `CookieManager` 가 리프래쉬 토큰을 쿠키로 만드는 기능에서 적당한 값을 쿠키로 만드는 기능으로 바꿈
  • Loading branch information
leegwichan committed Feb 4, 2025
1 parent aaeceea commit 412bf03
Show file tree
Hide file tree
Showing 12 changed files with 51 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
import com.debatetimer.dto.member.TableResponses;
import com.debatetimer.service.auth.AuthService;
import com.debatetimer.service.member.MemberService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseCookie;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -27,6 +27,8 @@
@RequiredArgsConstructor
public class MemberController {

private static final String REFRESH_TOKEN_COOKIE_KEY = "refreshToken";

private final MemberService memberService;
private final AuthService authService;
private final CookieManager cookieManager;
Expand All @@ -39,35 +41,41 @@ public TableResponses getTables(@AuthMember Member member) {

@PostMapping("/api/member")
@ResponseStatus(HttpStatus.CREATED)
public MemberCreateResponse createMember(@RequestBody MemberCreateRequest request, HttpServletResponse response) {
public ResponseEntity<MemberCreateResponse> createMember(@RequestBody MemberCreateRequest request) {
MemberInfo memberInfo = authService.getMemberInfo(request);
MemberCreateResponse memberCreateResponse = memberService.createMember(memberInfo);
JwtTokenResponse jwtTokenResponse = authManager.issueToken(memberInfo);
ResponseCookie refreshTokenCookie = cookieManager.createRefreshTokenCookie(jwtTokenResponse.refreshToken());
JwtTokenResponse jwtToken = authManager.issueToken(memberInfo);
ResponseCookie refreshTokenCookie = cookieManager.createCookie(REFRESH_TOKEN_COOKIE_KEY,
jwtToken.refreshToken(), jwtToken.refreshExpiration());

response.addHeader(HttpHeaders.AUTHORIZATION, jwtTokenResponse.accessToken());
response.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString());
return memberCreateResponse;
return ResponseEntity.status(HttpStatus.CREATED)
.header(HttpHeaders.AUTHORIZATION, jwtToken.accessToken())
.header(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString())
.body(memberCreateResponse);
}

@PostMapping("/api/member/reissue")
public void reissueAccessToken(HttpServletRequest request, HttpServletResponse response) {
String refreshToken = cookieManager.extractRefreshToken(request.getCookies());
JwtTokenResponse jwtTokenResponse = authManager.reissueToken(refreshToken);
ResponseCookie refreshTokenCookie = cookieManager.createRefreshTokenCookie(jwtTokenResponse.refreshToken());
public ResponseEntity<Void> reissueAccessToken(@CookieValue(REFRESH_TOKEN_COOKIE_KEY) String refreshToken) {
JwtTokenResponse jwtToken = authManager.reissueToken(refreshToken);
ResponseCookie refreshTokenCookie = cookieManager.createCookie(REFRESH_TOKEN_COOKIE_KEY,
jwtToken.refreshToken(), jwtToken.refreshExpiration());

response.addHeader(HttpHeaders.AUTHORIZATION, jwtTokenResponse.accessToken());
response.addHeader(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString());
return ResponseEntity.ok()
.header(HttpHeaders.AUTHORIZATION, jwtToken.accessToken())
.header(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString())
.build();
}

@PostMapping("/api/member/logout")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void logout(@AuthMember Member member, HttpServletRequest request, HttpServletResponse response) {
String refreshToken = cookieManager.extractRefreshToken(request.getCookies());
public ResponseEntity<Void> logout(@AuthMember Member member,
@CookieValue(REFRESH_TOKEN_COOKIE_KEY) String refreshToken) {
String email = authManager.resolveRefreshToken(refreshToken);
authService.logout(member, email);
ResponseCookie deletedRefreshTokenCookie = cookieManager.deleteRefreshTokenCookie();
ResponseCookie deletedRefreshTokenCookie = cookieManager.deleteCookie(REFRESH_TOKEN_COOKIE_KEY);

response.addHeader(HttpHeaders.SET_COOKIE, deletedRefreshTokenCookie.toString());
return ResponseEntity.noContent()
.header(HttpHeaders.SET_COOKIE, deletedRefreshTokenCookie.toString())
.build();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.debatetimer.controller.tool.cookie;

import com.debatetimer.controller.tool.jwt.JwtTokenProperties;
import jakarta.servlet.http.Cookie;
import java.time.Duration;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Service;
Expand All @@ -10,25 +9,13 @@
@RequiredArgsConstructor
public class CookieManager {

private static final String REFRESH_TOKEN_COOKIE_NAME = "refreshToken";

private final CookieProvider cookieProvider;
private final CookieExtractor cookieExtractor;
private final JwtTokenProperties jwtTokenProperties;

public ResponseCookie createRefreshTokenCookie(String token) {
return cookieProvider.createCookie(
REFRESH_TOKEN_COOKIE_NAME,
token,
jwtTokenProperties.getRefreshTokenExpiration()
);
}

public String extractRefreshToken(Cookie[] cookies) {
return cookieExtractor.extractCookie(REFRESH_TOKEN_COOKIE_NAME, cookies);
public ResponseCookie createCookie(String key, String value, Duration expiration) {
return cookieProvider.createCookie(key, value, expiration);
}

public ResponseCookie deleteRefreshTokenCookie() {
return cookieProvider.deleteCookie(REFRESH_TOKEN_COOKIE_NAME);
public ResponseCookie deleteCookie(String key) {
return cookieProvider.deleteCookie(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.debatetimer.dto.member.JwtTokenResponse;
import com.debatetimer.dto.member.MemberInfo;
import java.time.Duration;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand All @@ -15,15 +16,18 @@ public class AuthManager {
public JwtTokenResponse issueToken(MemberInfo memberInfo) {
String accessToken = jwtTokenProvider.createAccessToken(memberInfo);
String refreshToken = jwtTokenProvider.createRefreshToken(memberInfo);
return new JwtTokenResponse(accessToken, refreshToken);
Duration refreshTokenExpiration = jwtTokenProvider.getRefreshTokenExpiration();
return new JwtTokenResponse(accessToken, refreshToken, refreshTokenExpiration);
}

public JwtTokenResponse reissueToken(String refreshToken) {
String email = jwtTokenResolver.resolveRefreshToken(refreshToken);
MemberInfo memberInfo = new MemberInfo(email);

String accessToken = jwtTokenProvider.createAccessToken(memberInfo);
String newRefreshToken = jwtTokenProvider.createRefreshToken(memberInfo);
return new JwtTokenResponse(accessToken, newRefreshToken);
Duration refreshTokenExpiration = jwtTokenProvider.getRefreshTokenExpiration();
return new JwtTokenResponse(accessToken, newRefreshToken, refreshTokenExpiration);
}

public String resolveAccessToken(String accessToken) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,8 @@ private String createToken(MemberInfo memberInfo, Duration expiration, TokenType
.signWith(jwtTokenProperties.getSecretKey())
.compact();
}

public Duration getRefreshTokenExpiration() {
return jwtTokenProperties.getRefreshTokenExpiration();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.debatetimer.dto.member;

public record JwtTokenResponse(String accessToken, String refreshToken) {
import java.time.Duration;

public record JwtTokenResponse(String accessToken, String refreshToken, Duration refreshExpiration) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.debatetimer.DataBaseCleaner;
import com.debatetimer.client.OAuthClient;
import com.debatetimer.fixture.CookieGenerator;
import com.debatetimer.fixture.HeaderGenerator;
import com.debatetimer.fixture.MemberGenerator;
import com.debatetimer.fixture.ParliamentaryTableGenerator;
Expand Down Expand Up @@ -44,9 +43,6 @@ public abstract class BaseControllerTest {
@Autowired
protected HeaderGenerator headerGenerator;

@Autowired
protected CookieGenerator cookieGenerator;

@Autowired
protected TokenGenerator tokenGenerator;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import io.restassured.http.Header;
import io.restassured.http.Headers;
import io.restassured.specification.RequestSpecification;
import jakarta.servlet.http.Cookie;
import java.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
Expand All @@ -44,11 +44,9 @@ public abstract class BaseDocumentTest {
protected static String EXIST_MEMBER_ACCESS_TOKEN = "dflskgnkds";
protected static String EXIST_MEMBER_REFRESH_TOKEN = "dfsfsdgrs";
protected static JwtTokenResponse EXIST_MEMBER_TOKEN_RESPONSE = new JwtTokenResponse(EXIST_MEMBER_ACCESS_TOKEN,
EXIST_MEMBER_REFRESH_TOKEN);
EXIST_MEMBER_REFRESH_TOKEN, Duration.ofHours(1));
protected static Headers EXIST_MEMBER_HEADER = new Headers(
new Header(HttpHeaders.AUTHORIZATION, EXIST_MEMBER_ACCESS_TOKEN));
protected static Cookie EXIST_MEMBER_COOKIE = new Cookie("refreshToken", EXIST_MEMBER_REFRESH_TOKEN);
protected static Cookie DELETE_MEMBER_COOKIE = new Cookie("refreshToken", "");

protected static RestDocumentationResponse ERROR_RESPONSE = new RestDocumentationResponse()
.responseBodyField(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ class CreateMember {
doReturn(memberInfo).when(authService).getMemberInfo(request);
doReturn(response).when(memberService).createMember(memberInfo);
doReturn(EXIST_MEMBER_TOKEN_RESPONSE).when(authManager).issueToken(memberInfo);
doReturn(responseCookie(EXIST_MEMBER_REFRESH_TOKEN, 500)).when(cookieManager).createRefreshTokenCookie(EXIST_MEMBER_REFRESH_TOKEN);
doReturn(responseCookie(EXIST_MEMBER_REFRESH_TOKEN, 500)).when(cookieManager)
.createCookie(any(), any(), any());

var document = document("member/create", 201).request(requestDocument).response(responseDocument).build();

Expand Down Expand Up @@ -143,7 +144,8 @@ class ReissueAccessToken {
@Test
void 토큰_갱신_성공() {
doReturn(EXIST_MEMBER_TOKEN_RESPONSE).when(authManager).reissueToken(any());
doReturn(responseCookie(EXIST_MEMBER_REFRESH_TOKEN, 500)).when(cookieManager).createRefreshTokenCookie(any());
doReturn(responseCookie(EXIST_MEMBER_REFRESH_TOKEN, 500)).when(cookieManager)
.createCookie(any(), any(), any());

var document = document("member/logout", 204)
.request(requestDocument)
Expand All @@ -157,22 +159,6 @@ class ReissueAccessToken {
.then().statusCode(200);
}

@EnumSource(value = ClientErrorCode.class, names = {"EMPTY_COOKIE"})
@ParameterizedTest
void 토큰_갱신_실패_쿠키_추출(ClientErrorCode errorCode) {
doThrow(new DTClientErrorException(errorCode)).when(cookieManager).extractRefreshToken(any());

var document = document("member/reissue", errorCode)
.request(requestDocument)
.response(ERROR_RESPONSE)
.build();

given(document)
.cookie("refreshToken")
.when().post("/api/member/reissue")
.then().statusCode(errorCode.getStatus().value());
}

@EnumSource(value = ClientErrorCode.class, names = {"EXPIRED_TOKEN", "UNAUTHORIZED_MEMBER"})
@ParameterizedTest
void 토큰_갱신_실패_토큰_갱신(ClientErrorCode errorCode) {
Expand Down Expand Up @@ -205,7 +191,7 @@ class Logout {

@Test
void 로그아웃_성공() {
doReturn(responseCookie(EXIST_MEMBER_REFRESH_TOKEN, 0)).when(cookieManager).deleteRefreshTokenCookie();
doReturn(responseCookie(EXIST_MEMBER_REFRESH_TOKEN, 0)).when(cookieManager).deleteCookie(any());

var document = document("member/logout", 204)
.request(requestDocument)
Expand All @@ -218,23 +204,6 @@ class Logout {
.then().statusCode(204);
}

@EnumSource(value = ClientErrorCode.class, names = {"EMPTY_COOKIE"})
@ParameterizedTest
void 로그아웃_실패_쿠키_추출(ClientErrorCode errorCode) {
doThrow(new DTClientErrorException(errorCode)).when(cookieManager).extractRefreshToken(any());

var document = document("member/logout", errorCode)
.request(requestDocument)
.response(ERROR_RESPONSE)
.build();

given(document)
.headers(EXIST_MEMBER_HEADER)
.cookie("refreshToken")
.when().post("/api/member/logout")
.then().statusCode(errorCode.getStatus().value());
}

@EnumSource(value = ClientErrorCode.class, names = {"UNAUTHORIZED_MEMBER", "EXPIRED_TOKEN"})
@ParameterizedTest
void 로그아웃_실패(ClientErrorCode errorCode) {
Expand Down

This file was deleted.

37 changes: 0 additions & 37 deletions src/test/java/com/debatetimer/fixture/CookieGenerator.java

This file was deleted.

Loading

0 comments on commit 412bf03

Please sign in to comment.