Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEAT] 액세스토큰 쿠키에서 jwt 사용 - #154 #155

Merged
merged 2 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cakey.common.filter;

import com.cakey.Constants;
import com.cakey.jwt.auth.JwtProvider;
import com.cakey.jwt.auth.UserAuthentication;
import jakarta.servlet.FilterChain;
Expand All @@ -12,6 +13,7 @@

import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.apache.tomcat.util.http.parser.Authorization;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
Expand All @@ -21,8 +23,6 @@
public class OptionalAuthenticationFilter extends OncePerRequestFilter { //로그인 상관 X
private final JwtProvider jwtProvider;

private static final String ACCESS_TOKEN = "accessToken";

// 필터를 건너뛸 API 경로 목록
private static final List<String> EXCLUDED_PATHS = List.of(
"/api/v1/store/likes/latest/*",
Expand All @@ -43,7 +43,8 @@ public class OptionalAuthenticationFilter extends OncePerRequestFilter { //로
"/api/v1/store/*/select/coordinate",
"/api/v1/store/*/size",
"/api/v1/store/*/information",
"/api/v1/store/*/kakaoLink"
"/api/v1/store/*/kakaoLink",
"api/v1/user/login"
);

@Override
Expand All @@ -60,26 +61,19 @@ protected void doFilterInternal(
@NonNull FilterChain filterChain
) throws ServletException, IOException {

final String accessToken = getAccessTokenFromCookie(request);
final String accessToken = request.getHeader(Constants.AUTHORIZATION);

if (accessToken != null) {
final Long userId = jwtProvider.getUserIdFromSubject(accessToken);
SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(userId, null, null));
final long userId = jwtProvider.getUserIdFromSubject(accessToken);
SecurityContextHolder
.getContext()
.setAuthentication(new UserAuthentication(userId, null, null));
} else {
SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(null, null, null));
SecurityContextHolder
.getContext()
.setAuthentication(new UserAuthentication(null, null, null));
}

filterChain.doFilter(request, response);
}

public String getAccessTokenFromCookie(@NonNull HttpServletRequest request) {
final Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (ACCESS_TOKEN.equals(cookie.getName())) {
return cookie.getValue();
}
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ public class RequiredAuthenticationFilter extends OncePerRequestFilter {
"/api/v1/store/*/select/coordinate",
"/api/v1/store/*/size",
"/api/v1/store/*/information",
"/api/v1/store/*/kakaoLink"
"/api/v1/store/*/kakaoLink",
"api/v1/user/login"

);

Expand All @@ -68,9 +69,13 @@ protected void doFilterInternal(
@NonNull FilterChain filterChain
) throws ServletException, IOException {
try {
final String token = getAccessTokenFromCookie(request);
final Long userId = jwtProvider.getUserIdFromSubject(token);
SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(userId, null, null));
final String accessToken = request.getHeader(Constants.AUTHORIZATION);
final long userId = jwtProvider.getUserIdFromSubject(accessToken);

SecurityContextHolder
.getContext()
.setAuthentication(new UserAuthentication(userId, null, null));

filterChain.doFilter(request, response); // 다음 필터로 요청 전달
} catch (Exception e) {
// 예외 발생 시 JSON 응답 생성
Expand All @@ -80,7 +85,7 @@ protected void doFilterInternal(
response.setCharacterEncoding(Constants.CHARACTER_TYPE);
response.setStatus(errorCode.getHttpStatus().value()); // HTTP 상태 코드 401 설정

log.error("--------------------쿠키 없음------------------------"); //todo: 추후 삭제(테스트용)
log.error("--------------------토큰 없음------------------------"); //todo: 추후 삭제(테스트용)
// `ApiResponseUtil.failure`를 이용해 응답 작성
final PrintWriter writer = response.getWriter();
writer.write(objectMapper.writeValueAsString(
Expand All @@ -90,16 +95,4 @@ protected void doFilterInternal(
return; // 체인 호출 중단
}
}

private String getAccessTokenFromCookie(final HttpServletRequest request) throws Exception {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for(Cookie cookie : cookies) {
if (cookie.getName().equals("accessToken")) {
return cookie.getValue();
}
}
}
throw new UserBadRequestException(ErrorBaseCode.UNAUTHORIZED);
}
}
44 changes: 9 additions & 35 deletions cakey-api/src/main/java/com/cakey/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.cakey.user.service;


import com.cakey.Constants;
import com.cakey.client.SocialType;
import com.cakey.client.dto.LoginReq;
import com.cakey.client.kakao.api.KakaoSocialService;
Expand All @@ -27,6 +28,7 @@
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
Expand All @@ -37,12 +39,9 @@ public class UserService {
private final UserFacade userFacade;
private final KakaoSocialService kakaoSocialService;

private final static String ACCESS_TOKEN = "accessToken";
private final static String REFRESH_TOKEN = "refreshToken";
private final JwtProvider jwtProvider;
private final UserRetriever userRetriever;


@Transactional
public LoginSuccessRes login(
final String authorizationCode,
final SocialType socialType,
Expand All @@ -62,7 +61,6 @@ public LoginSuccessRes login(
throw new UserBadRequestException(UserErrorCode.KAKAO_LOGIN_FAILED);
}


//플랫폼 아이디
final long platformId = kakaoUserInfo.id();

Expand All @@ -78,12 +76,12 @@ public LoginSuccessRes login(
final Token newToken = jwtProvider.issueToken(savedUserId);

//쿠키설정
setAccessCookie(newToken.getAccessToken(), response);
setRefreshCookie(newToken.getRefreshToken(), response);

return LoginSuccessRes.of(
savedUserId,
kakaoUserInfo.kakaoAccount().profile().nickname());
kakaoUserInfo.kakaoAccount().profile().nickname(),
newToken.getAccessToken());
} else { //전에 이미 우리 유저

//리프레시 토큰 캐시 삭제
Expand All @@ -92,12 +90,12 @@ public LoginSuccessRes login(
final Token newToken = jwtProvider.issueToken(userId);

//쿠키 설정
setAccessCookie(newToken.getAccessToken(), response);
setRefreshCookie(newToken.getRefreshToken(), response);

return LoginSuccessRes.of(
userId,
kakaoUserInfo.kakaoAccount().profile().nickname());
kakaoUserInfo.kakaoAccount().profile().nickname(),
newToken.getAccessToken());
}
}

Expand All @@ -114,29 +112,16 @@ public void logout(final long userId, final HttpServletResponse response) {
} catch (NotFoundBaseException e) {
throw new UserNotFoundException(UserErrorCode.USER_NOT_FOUND);
}
deleteAccessCookie(response);
deleteRefreshCookie(response);
deleteRefreshToken(userId);
}

@CacheEvict(value = "refresh")
public void deleteRefreshToken(final long userId) { }

//accessToken 쿠키 삭제
public void deleteAccessCookie(HttpServletResponse response) {
ResponseCookie accessCookie = ResponseCookie.from(ACCESS_TOKEN, "")
.maxAge(0) // 쿠키 즉시 삭제
.path("/")
.secure(true)
.sameSite("None")
.httpOnly(true)
.build();
response.addHeader("Set-Cookie", accessCookie.toString());
}

//refreshToken 쿠키 삭제
public void deleteRefreshCookie(HttpServletResponse response) {
ResponseCookie refreshCookie = ResponseCookie.from(REFRESH_TOKEN, "")
ResponseCookie refreshCookie = ResponseCookie.from(Constants.REFRESH_TOKEN, "")
.maxAge(0) // 쿠키 즉시 삭제
.path("/")
.secure(true)
Expand All @@ -146,19 +131,8 @@ public void deleteRefreshCookie(HttpServletResponse response) {
response.addHeader("Set-Cookie", refreshCookie.toString());
}

public void setAccessCookie(final String accessToken, final HttpServletResponse response) {
ResponseCookie accessCookie = ResponseCookie.from(ACCESS_TOKEN, accessToken)
.maxAge(30 * 24 * 60 * 60 * 1000L) /// 1달
.path("/")
.secure(true)
.sameSite("None")
.httpOnly(true)
.build();
response.setHeader("Set-Cookie", accessCookie.toString());
}

public void setRefreshCookie(final String refreshToken, final HttpServletResponse response) {
ResponseCookie refreshCookie = ResponseCookie.from(REFRESH_TOKEN, refreshToken)
ResponseCookie refreshCookie = ResponseCookie.from(Constants.REFRESH_TOKEN, refreshToken)
.maxAge(30 * 24 * 60 * 60 * 1000L) /// 1달
.path("/")
.secure(true)
Expand Down
2 changes: 2 additions & 0 deletions cakey-common/src/main/java/com/cakey/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ public abstract class Constants {
public static final String CHARACTER_TYPE = "utf-8";
public static final String BEARER = "Bearer ";
public static final String AUTHCODE = "authorization_code";
public static final String AUTHORIZATION = "Authorization";
public static final String REFRESH_TOKEN = "refreshToken";

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@
@Builder(access = AccessLevel.PRIVATE)
public record LoginSuccessRes(
long userId,
String userName
String userName,
String accessToken
) {
public static LoginSuccessRes of(
final long userId,
final String userName) {
return LoginSuccessRes.builder().userId(userId).userName(userName).build();
final String userName,
final String accessToken) {
return LoginSuccessRes.builder()
.userId(userId)
.userName(userName)
.accessToken(accessToken)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,9 @@
public class UserCreator {
private final UserRepository userRepository;

@Transactional
public long createUser(final UserCreateDto userCreateDto) {
final User user = User.createUser(userCreateDto.userName(), userCreateDto.userRole(),
userCreateDto.socialType(), userCreateDto.socialId(), userCreateDto.socialEmail());
System.out.println();
final User savedUser = userRepository.save(user);
return savedUser.getId();
}
Expand Down