diff --git a/src/docs/asciidoc/settlement.adoc b/src/docs/asciidoc/settlement.adoc index 88e7983..58cfd1c 100644 --- a/src/docs/asciidoc/settlement.adoc +++ b/src/docs/asciidoc/settlement.adoc @@ -6,7 +6,7 @@ 모임을 생성할 수 있습니다. -- 모임을 생성하는 사용자의 `accessToken`이 필요합니다. +- 모임을 생성하는 사용자의 인증 쿠키(`accessToken`)가 필요합니다. - 생성할 모임의 이름을 요청 본문에 포함합니다. - 생성된 모임의 ID, 생성자(정산 담당자) ID, 생성 시간, 만료 시간, 계좌 정보를 확인할 수 있습니다. - 비회원이 생성한 모임은 1개월 후 자동 삭제됩니다. diff --git a/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtProperties.java b/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtProperties.java index 934c958..aafa317 100644 --- a/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtProperties.java +++ b/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtProperties.java @@ -13,17 +13,18 @@ public class JwtProperties { private final String header; private final String prefix; + private final String accessCookieName; private final SecretKey secretKey; private final Long accessExpiration; private final Long refreshExpiration; - public JwtProperties(String header, String prefix, String secretKey, Long accessExpiration, - Long refreshExpiration) { + public JwtProperties(String header, String prefix, String accessCookieName, String secretKey, + Long accessExpiration, Long refreshExpiration) { this.header = header; this.prefix = prefix; + this.accessCookieName = accessCookieName; this.secretKey = Keys.hmacShaKeyFor(Decoders.BASE64.decode(secretKey)); this.accessExpiration = accessExpiration; this.refreshExpiration = refreshExpiration; } } - diff --git a/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtUtil.java b/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtUtil.java index d0d56c7..dfed8f0 100644 --- a/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtUtil.java +++ b/src/main/java/com/dnd/moddo/auth/infrastructure/security/JwtUtil.java @@ -8,6 +8,7 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; +import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; @Component @@ -19,10 +20,34 @@ public JwtUtil(JwtProperties jwtProperties) { } public String resolveToken(HttpServletRequest request) { + String cookieToken = resolveTokenFromCookie(request); + if (cookieToken != null) { + return cookieToken; + } + String bearer = request.getHeader(jwtProperties.getHeader()); return parseToken(bearer); } + private String resolveTokenFromCookie(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies == null) { + return null; + } + + for (Cookie cookie : cookies) { + if (jwtProperties.getAccessCookieName().equals(cookie.getName())) { + String value = cookie.getValue(); + if (value == null || value.isBlank()) { + return null; + } + return value; + } + } + + return null; + } + public String parseToken(String bearer) { if (bearer != null && bearer.startsWith(jwtProperties.getPrefix())) { return bearer.replace(jwtProperties.getPrefix(), "").trim(); @@ -45,4 +70,4 @@ public Long getIdFromToken(String token, String key) { Claims claims = getJwt(token).getBody(); return claims.get(key, Long.class); } -} \ No newline at end of file +} diff --git a/src/main/resources/config b/src/main/resources/config index d25ada6..3d98bab 160000 --- a/src/main/resources/config +++ b/src/main/resources/config @@ -1 +1 @@ -Subproject commit d25ada6852687393698080ae28655aa91c6acbe7 +Subproject commit 3d98bab8fe3c64bb6a96fd1755d247cf7d19586d diff --git a/src/test/java/com/dnd/moddo/domain/auth/service/JwtUtilTest.java b/src/test/java/com/dnd/moddo/domain/auth/service/JwtUtilTest.java new file mode 100644 index 0000000..45eb966 --- /dev/null +++ b/src/test/java/com/dnd/moddo/domain/auth/service/JwtUtilTest.java @@ -0,0 +1,66 @@ +package com.dnd.moddo.domain.auth.service; + +import static org.assertj.core.api.Assertions.*; + +import org.junit.jupiter.api.Test; +import org.springframework.mock.web.MockHttpServletRequest; + +import com.dnd.moddo.auth.infrastructure.security.JwtProperties; +import com.dnd.moddo.auth.infrastructure.security.JwtUtil; + +import jakarta.servlet.http.Cookie; + +class JwtUtilTest { + + private final JwtUtil jwtUtil = new JwtUtil( + new JwtProperties( + "Authorization", + "Bearer", + "accessToken", + "c2VjcmV0S2V5c2VjcmV0S2V5c2VjcmV0S2V5c2VjcmV0S2V5c2VjcmV0S2V5", + 1L, + 1L + ) + ); + + @Test + void givenAccessTokenCookie_thenResolveTokenFromCookie() { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setCookies(new Cookie("accessToken", "cookie-token")); + request.addHeader("Authorization", "Bearer header-token"); + + // when + String token = jwtUtil.resolveToken(request); + + // then + assertThat(token).isEqualTo("cookie-token"); + } + + @Test + void givenAuthorizationHeaderWithoutCookie_thenResolveTokenFromHeader() { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", "Bearer header-token"); + + // when + String token = jwtUtil.resolveToken(request); + + // then + assertThat(token).isEqualTo("header-token"); + } + + @Test + void givenBlankAccessTokenCookie_thenResolveTokenFromHeader() { + // given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setCookies(new Cookie("accessToken", " ")); + request.addHeader("Authorization", "Bearer header-token"); + + // when + String token = jwtUtil.resolveToken(request); + + // then + assertThat(token).isEqualTo("header-token"); + } +} diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index 0064479..5f56ee7 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -27,6 +27,7 @@ spring: jwt: header: Authorization prefix: prefix + access-cookie-name: accessToken secret-key: secretKeysecretKeysecretKeysecretKeysecretKeysecretKey access-expiration: 1 refresh-expiration: 1