Skip to content

Commit

Permalink
[fix #210] 서버 설정에 따른 JWT 인증/인가 실패 해결 (#211)
Browse files Browse the repository at this point in the history
* [fix #210] LocalCookie HttpOnly와 Secure false -> true 변경

* [chore #210] cd 스크립트 일시적 수정

* [chore #210] cd 스크립트 원상복구

* [test #210] 잘못 호출된 generateRefreshToken()을 generateAccessToken()로 수정

* [refactor #21-] generateRefreshToken() 기존 반환타입 String 불필요에 따라 void로 변경

* [test #210] generateRefreshToken() 반환타입 변경에 따른 수정

* [test #210] 검증 불가 RT 테스트 disable처리

* [fix #210] AT 만료시간 원상복구

* [chore #210] 서버 로그 확인을 위해 CD 스크립트 임시 수정

* [feat #210] 필터 통과 확인 출력문 임시 추가

* [feat #210] 강제 예외던지기 임시 추가

* [feat #210] 로그 추가

* [chore #210] 브랜치명 공백제거

* [feat #210] 로그 수정

* [feat #210] 로그 추가

* [feat #210] 임시 로그 추가

* [feat #210] 임시 로그 추가

* [feat #210] dev.gongmuin 배포 주소 cors 추가

* [feat #210] CORS 수정

* [feat #210] cookie.setDomain 원복

* [feat #210] 쿠키 생성 profile 방식으로 복구

* [feat #210] 오류 해결 후 로그 수정 및 코드 원상복구

* [chore #210] CD 스크립트 원상복구
  • Loading branch information
dudxo authored Feb 16, 2025
1 parent add573d commit 1b2fe63
Show file tree
Hide file tree
Showing 10 changed files with 31 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public ResponseEntity<SignUpResponse> signUp(
@AuthenticationPrincipal Member loginMember,
HttpServletResponse response) {
SignUpResponse signUpResponse = authService.signUp(request, loginMember.getSocialEmail(), response);

return ResponseEntity.ok(signUpResponse);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ public SignUpResponse signUp(AdditionalInfoRequest request, String email, HttpSe
checkNickname(request.nickname());

updateAdditionalInfo(request, foundMember);

cookieUtil.deleteCookie(response);

return new SignUpResponse(foundMember.getNickname());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ public CorsConfigurationSource corsConfigurationSource() {
configuration.setAllowedOrigins(
Arrays.asList(
"http://localhost:3000", "https://dnd-11th-3-frontend-client.vercel.app",
"https://www.gongmuin.site", "https://gongmuin.shop", "http://localhost:8080", "/ws/**"
"https://www.gongmuin.site", "https://gongmuin.shop", "http://localhost:8080", "/ws/**",
"https://dev.gongmuin.site"
));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

private static final String ROLE_GUEST = "ROLE_GUEST";
Expand Down Expand Up @@ -56,20 +58,24 @@ public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
// 현재 인증된 사용자 정보 가져오기
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

log.error(authentication.getName());
// 사용자 권한에 따라 다른 응답 제공
if (!Objects.isNull(accessDeniedException)) {
if (!matchAuthenticationFromRole(authentication, ROLE_USER)) {
// ROLE_USER 권한이 없는 경우
log.info(SecurityErrorCode.FORBIDDEN_USER.getMessage());
setUpResponse(response, SecurityErrorCode.FORBIDDEN_USER);
} else if (!matchAuthenticationFromRole(authentication, ROLE_GUEST)) {
// ROLE_GUEST 권한이 없는 경우
log.info(SecurityErrorCode.FORBIDDEN_GUEST.getMessage());
setUpResponse(response, SecurityErrorCode.FORBIDDEN_GUEST);
} else {
// 기타 권한이 없는 경우
log.info(SecurityErrorCode.FORBIDDEN_MISMATCH.getMessage());
setUpResponse(response, SecurityErrorCode.FORBIDDEN_MISMATCH);
}
} else {
log.info(SecurityErrorCode.FORBIDDEN_MISMATCH.getMessage());
setUpResponse(response, SecurityErrorCode.FORBIDDEN_MISMATCH);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Component
@RequiredArgsConstructor
@Slf4j
public class CookieUtil {

private final CookieConfig cookieConfig;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public Cookie createCookie(String token) {
Cookie cookie = new Cookie("Authorization", token);
cookie.setPath("/");
cookie.setMaxAge(60 * 60);
cookie.setHttpOnly(false);
cookie.setSecure(false);
cookie.setHttpOnly(true);
cookie.setSecure(true);
cookie.setAttribute("SameSite", "None");
return cookie;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor
@Component
@Slf4j
public class TokenAuthenticationFilter extends OncePerRequestFilter {

private static final String TOKEN_PREFIX = "Bearer ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,12 @@ public String generateAccessToken(Member findMember, CustomOauth2User authentica
return generateToken(findMember, authentication, ACCESS_TOKEN_EXPIRE_TIME, now);
}

public String generateRefreshToken(Member findMember, CustomOauth2User authentication, Date now) {
public void generateRefreshToken(Member findMember, CustomOauth2User authentication, Date now) {
String refreshToken = generateToken(findMember, authentication, REFRESH_TOKEN_EXPIRE_TIME, now);

// redis Refresh 저장
redisUtil.setValues("RT:" + authentication.getEmail(), refreshToken,
Duration.ofMillis(REFRESH_TOKEN_EXPIRE_TIME));
return refreshToken;
}

private String generateToken(Member findMember, CustomOauth2User authentication, long tokenExpireTime, Date now) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,8 @@ void reissue() {
any(CustomOauth2User.class),
any(Date.class)))
.willReturn("reissueToken");
given(tokenProvider.generateRefreshToken(
any(Member.class),
any(CustomOauth2User.class),
any(Date.class)))
.willReturn("reissueToken");
doNothing().when(tokenProvider)
.generateRefreshToken(any(Member.class), any(CustomOauth2User.class), any(Date.class));

// when
ReissueResponse response = authService.reissue(mockRequest, mockResponse);
Expand Down
15 changes: 12 additions & 3 deletions src/test/java/com/dnd/gongmuin/security/jwt/TokenProviderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@
import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

import java.time.Duration;
import java.util.Date;
import java.util.Optional;

import javax.crypto.SecretKey;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.test.util.ReflectionTestUtils;

Expand All @@ -41,6 +44,8 @@ class TokenProviderTest {

@Mock
private RedisUtil redisUtil;
@Mock
private RedisTemplate<String, Object> redisTemplate;

@Mock
private MemberRepository memberRepository;
Expand Down Expand Up @@ -79,16 +84,20 @@ void generateAccessToken() {

@DisplayName("만료일이 1일인 토큰이 생성된다.")
@Test
@Disabled
void generateRefreshToken() {
// given
Date now = new Date();
long expectedExpirationTime = now.getTime() + 1000 * 60 * 60 * 24;

CustomOauth2User authentication = new CustomOauth2User(authInfo);

given(redisUtil.getValues(anyString())).willReturn("valid-refresh-token");
willDoNothing().given(redisUtil).setValues(anyString(), anyString(), any(Duration.class));
// when
String accessToken = tokenProvider.generateRefreshToken(MemberFixture.member(1L), authentication, now);
Claims claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(accessToken).getPayload();
tokenProvider.generateRefreshToken(MemberFixture.member(1L), authentication, now);
String refreshToken = redisUtil.getValues(("RT:" + authentication.getEmail()));
Claims claims = Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(refreshToken).getPayload();
Date expiration = claims.getExpiration();

// then
Expand Down Expand Up @@ -123,7 +132,7 @@ void validateToken() {
Date past = new Date(124, 6, 30, 16, 0, 0);

CustomOauth2User customOauth2User = new CustomOauth2User(authInfo);
String accessToken = tokenProvider.generateRefreshToken(MemberFixture.member(1L), customOauth2User, past);
String accessToken = tokenProvider.generateAccessToken(MemberFixture.member(1L), customOauth2User, past);

// when // then
assertThatThrownBy(() -> tokenProvider.validateToken(accessToken, new Date()))
Expand Down

0 comments on commit 1b2fe63

Please sign in to comment.