Skip to content

Commit

Permalink
merge: 필터 예외 처리 추가 - #138
Browse files Browse the repository at this point in the history
[FEAT] 필터 예외 처리 추가 - #138
  • Loading branch information
sjk4618 authored Jan 23, 2025
2 parents 1f61b0a + 24c5c8b commit 5edf171
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 20 deletions.
5 changes: 5 additions & 0 deletions cakey-api/src/main/java/com/cakey/common/Constant.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.cakey.common;

public abstract class Constant {
public static final String CHARACTER_TYPE = "utf-8";
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package com.cakey.common.filter;

import com.cakey.common.Constant;
import com.cakey.common.response.ApiResponseUtil;
import com.cakey.jwt.auth.JwtProvider;
import com.cakey.jwt.auth.UserAuthentication;
import com.cakey.jwt.auth.JwtValidationType;
import com.cakey.rescode.ErrorBaseCode;
import com.cakey.rescode.ErrorCode;
import com.cakey.user.exception.UserBadRequestException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
Expand All @@ -24,6 +30,7 @@
@RequiredArgsConstructor
public class RequiredAuthenticationFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider; //로그인 필수
private final ObjectMapper objectMapper;

// 필터를 건너뛸 API 경로 목록
private static final List<String> EXCLUDED_PATHS = List.of(
Expand Down Expand Up @@ -63,13 +70,25 @@ protected void doFilterInternal(
) throws ServletException, IOException {
try {
final String token = getAccessTokenFromCookie(request);

final Long userId = jwtProvider.getUserIdFromSubject(token);
SecurityContextHolder.getContext().setAuthentication(new UserAuthentication(userId, null, null));
filterChain.doFilter(request, response); // 다음 필터로 요청 전달
} catch (Exception e) {
throw new UserBadRequestException(ErrorBaseCode.UNAUTHORIZED);
// 예외 발생 시 JSON 응답 생성
final ErrorBaseCode errorCode = ErrorBaseCode.UNAUTHORIZED;

response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setCharacterEncoding(Constant.CHARACTER_TYPE);
response.setStatus(errorCode.getHttpStatus().value()); // HTTP 상태 코드 401 설정

// `ApiResponseUtil.failure`를 이용해 응답 작성
final PrintWriter writer = response.getWriter();
writer.write(objectMapper.writeValueAsString(
ApiResponseUtil.failure(errorCode).getBody()
));
writer.flush();
return; // 체인 호출 중단
}
filterChain.doFilter(request, response);
}

private String getAccessTokenFromCookie(final HttpServletRequest request) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
@RequiredArgsConstructor
public enum UserErrorCode implements ErrorCode {

/**
* 404 Not Found
*/


/**
* 404 Not Found
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public void deleteRefreshCookie(HttpServletResponse response) {

public void setAccessCookie(final String accessToken, final HttpServletResponse response) {
ResponseCookie accessCookie = ResponseCookie.from(ACCESS_TOKEN, accessToken)
.maxAge(14* 24 * 60 * 60 * 1000L) //액세스 토큰 기간 2주
.maxAge(30 * 24 * 60 * 60 * 1000L) /// 1달
.path("/")
.secure(true)
.sameSite("None")
Expand All @@ -158,7 +158,7 @@ public void setAccessCookie(final String accessToken, final HttpServletResponse

public void setRefreshCookie(final String refreshToken, final HttpServletResponse response) {
ResponseCookie refreshCookie = ResponseCookie.from(REFRESH_TOKEN, refreshToken)
.maxAge(14* 24 * 60 * 60 * 1000L) //리프레시 토큰 기간 2주
.maxAge(30 * 24 * 60 * 60 * 1000L) /// 1달
.path("/")
.secure(true)
.sameSite("None")
Expand Down
21 changes: 11 additions & 10 deletions cakey-auth/src/main/java/com/cakey/jwt/auth/JwtGenerator.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.cakey.jwt.auth;

import com.cakey.jwt.domain.Token;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jws;
Expand All @@ -18,16 +19,12 @@
@RequiredArgsConstructor
@Component
public class JwtGenerator {

//todo: 추후에 properties로 가져오기(데로 참고)
private static final Long ACCESS_TOKEN_EXPIRATION_TIME = 14* 24 * 60 * 60 * 1000L; //2시간
private static final Long REFRESH_TOKEN_EXPIRATION_TIME = 14* 24 * 60 * 60 * 1000L; //2주
private static final String SECRET_KEY = "cakeyfsdafasdfjsadrhksadrhskdlrskadjlralsdkrhasdklrhsadr";
private final JwtProperties jwtProperties;

//액세스 토큰 발급
public String generateAccessToken(final long userId) {
final Date now = new Date();
final Date expireDate = generateExpirationDate(now);
final Date expireDate = generateExpirationDate(now, true);

return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
Expand All @@ -41,7 +38,7 @@ public String generateAccessToken(final long userId) {
@Cacheable(value = "refresh")
public String generateRefreshToken(final long userId) {
final Date now = new Date();
final Date expireDate = generateExpirationDate(now);
final Date expireDate = generateExpirationDate(now, false);

return Jwts.builder()
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
Expand All @@ -52,16 +49,20 @@ public String generateRefreshToken(final long userId) {
.compact();
}

private Date generateExpirationDate(final Date now) {
return new Date(now.getTime() + ACCESS_TOKEN_EXPIRATION_TIME);
private Date generateExpirationDate(final Date now, final boolean isAccessToken) {
if (isAccessToken) {
return new Date(now.getTime() + jwtProperties.getAccessTokenExpirationTime());
} else {
return new Date(now.getTime() + jwtProperties.getRefreshTokenExpirationTime());
}
}

public Key getSigningKey() {
return Keys.hmacShaKeyFor(encodeSecretKeyToBase64().getBytes());
}

private String encodeSecretKeyToBase64() {
return Base64.getEncoder().encodeToString(SECRET_KEY.getBytes());
return Base64.getEncoder().encodeToString(jwtProperties.getSecret().getBytes());
}

public Jws<Claims> parseToken(final String token) {
Expand Down
17 changes: 17 additions & 0 deletions cakey-auth/src/main/java/com/cakey/jwt/auth/JwtProperties.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.cakey.jwt.auth;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Getter
@Setter
@ConfigurationProperties("jwt")
@Component
public class JwtProperties {
private String secret;
private long accessTokenExpirationTime;
private long refreshTokenExpirationTime;

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ public enum ErrorBaseCode implements ErrorCode {
BAD_REQUEST_MISSING_PARAM(HttpStatus.BAD_REQUEST, 40003, "필수 param이 없습니다."),
BAD_REQUEST_METHOD_ARGUMENT_TYPE(HttpStatus.BAD_REQUEST, 40004, "메서드 인자타입이 잘못되었습니다."),
BAD_REQUEST_NOT_READABLE(HttpStatus.BAD_REQUEST, 40005, "json 오류 혹은 reqeust body 필드 오류 입니다."),
BAD_REQUEST_ENUM_VALUE(HttpStatus.BAD_REQUEST, 40006, "잘못된 enum 값입니다."),

/**
* 401 Unauthorized
Expand Down

0 comments on commit 5edf171

Please sign in to comment.