3
3
import com .fasterxml .jackson .databind .ObjectMapper ;
4
4
import devkor .ontime_back .entity .User ;
5
5
import devkor .ontime_back .repository .UserRepository ;
6
- import devkor .ontime_back .response .ApiResponseForm ;
7
- import devkor .ontime_back .response .ErrorCode ;
8
- import devkor .ontime_back .response .InvalidTokenException ;
6
+ import devkor .ontime_back .response .*;
9
7
import jakarta .servlet .DispatcherType ;
10
8
import jakarta .servlet .FilterChain ;
11
9
import jakarta .servlet .http .HttpServletRequest ;
33
31
@ Slf4j
34
32
public class JwtAuthenticationFilter extends OncePerRequestFilter {
35
33
36
- private static final List <String > NO_CHECK_URLS = List .of ("/login" , "/swagger-ui" , "/sign-up" , "/v3/api-docs" ); // "/login"으로 들어오는 요청은 Filter 작동 X
34
+ private static final List <String > NO_CHECK_URLS = List .of ("/login" , "/swagger-ui" , "/sign-up" , "/v3/api-docs" , "/oauth2/google/registerOrLogin" , "/oauth2/kakao/registerOrLogin" , "/oauth2/apple/registerOrLogin" );
37
35
38
36
private final JwtTokenProvider jwtTokenProvider ;
39
37
private final UserRepository userRepository ;
@@ -55,19 +53,29 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
55
53
String refreshToken = jwtTokenProvider .extractRefreshToken (request )
56
54
.orElse (null );
57
55
58
- if (refreshToken != null ) {
59
- checkRefreshTokenAndReIssueAccessToken (response , refreshToken );
56
+ // 리프레시 토큰이 있고, 유효할 경우 엑세스토큰 재발급
57
+ // 이때 조건절의 isRefreshTokenValid에서 토큰이 유효하지 않으면 InvalidRefreshTokenException 발생
58
+ if (refreshToken != null && jwtTokenProvider .isRefreshTokenValid (refreshToken )) {
59
+ // 리프레시토큰의 경우 토큰의 유효성 뿐만 아니라 DB에 등록되어 있는지도 확인해야 함
60
+ // reIssueAccessToken 메소드에서 DB를 확인해 등록된 리프레시 토큰이면 엑세스 토큰 재발급
61
+ // 이때 reIssueAccessToken 메소드에서 DB에 등록된 리프레시 토큰이 아니면 InvalidRefreshTokenException 발생
62
+ log .info ("리프레시 토큰이 있고 유효한데 DB에 있는지는 아직 모름" );
63
+ reIssueAccessToken (response , refreshToken );
60
64
return ;
61
65
}
62
66
63
- if (accessToken != null && jwtTokenProvider .isTokenValid (accessToken )) {
67
+ // 리프레시 토큰이 있을 때의 처리는 위의 if문에서 처리하였음.
68
+ // 이제부터는 엑세스 토큰'만' 헤더에 담긴 요청만 생각하면 됨
69
+
70
+ // 엑세스 토큰이 있고, 유효할 경우 checkAccessTokenAndAuthentication 메서드 호출해 권한정보 저장하고 스프링 시큐리티 필터체인 계속 진행
71
+ if (accessToken != null && jwtTokenProvider .isAccessTokenValid (accessToken )) {
64
72
checkAccessTokenAndAuthentication (request , response , filterChain );
65
- return ;
66
73
}
67
74
68
- if (accessToken != null && !jwtTokenProvider .isTokenValid (accessToken )) {
69
- response .sendError (HttpServletResponse .SC_FORBIDDEN , "Invalid Access token." );
70
- return ;
75
+ // 엑세스 토큰이 없는 경우 EmptyAccessTokenException 발생
76
+ // 엑세스 토큰 없고 리프레시 토큰 있는 경우는 첫번째 if문에서 처리하여서 고려하지 않아도 됨.
77
+ if (accessToken == null ) {
78
+ throw new EmptyAccessTokenException ("Empty Access token!~!" );
71
79
}
72
80
73
81
@@ -78,27 +86,21 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
78
86
79
87
}
80
88
81
- // refreshToken로 검색 후 accessToken 재발급 후 전송
82
- public void checkRefreshTokenAndReIssueAccessToken (HttpServletResponse response , String refreshToken ) throws IOException {
83
- if (!jwtTokenProvider .isTokenValid (refreshToken )) {
84
- response .sendError (HttpServletResponse .SC_UNAUTHORIZED , "Invalid Refresh token." );
85
- }
86
-
87
- userRepository .findByRefreshToken (refreshToken ) // refreshToken으로 유저 찾기
88
- .ifPresent (user -> {
89
- String newAccessToken = jwtTokenProvider .createAccessToken (user .getEmail (), user .getId ()); // accessToken 생성
90
- log .info ("New accessToken issued: " + newAccessToken ); // 재발급된 accessToken 출력
91
- jwtTokenProvider .sendAccessToken (response , newAccessToken ); // accessToken 전송
92
- // jwtTokenProvider.sendAccessToken(response, jwtTokenProvider.createAccessToken(user.getEmail(), user.getId())); // accessToken 생성 후 전송
93
- });
89
+ // 리프레시 토큰이 DB에 있으면 엑세스 토큰을 재발급
90
+ // DB에 없으면 InvalidRefreshTokenException 발생
91
+ public void reIssueAccessToken (HttpServletResponse response , String refreshToken ) throws IOException {
92
+ log .info ("리프레시토큰이 유효하나 DB에 있는지는 모름. DB에서 찾아봐서 없으면 예외 발생할 것임." );
93
+ User user = userRepository .findByRefreshToken (refreshToken )
94
+ .orElseThrow (() -> new InvalidRefreshTokenException ("Invalid Refresh token!~!" ));
95
+ log .info ("리프레시토큰이 DB에도 있음" );
96
+ jwtTokenProvider .sendAccessToken (response , jwtTokenProvider .createAccessToken (user .getEmail (), user .getId ()));
94
97
}
95
98
96
- // accessToken 확인 후 인증 확인
99
+ // accessToken으로 유저의 권한정보만 저장하고 인증 허가(스프링 시큐리티 필터체인 中 인증체인 통과해 다음 체인으로 이동)
97
100
public void checkAccessTokenAndAuthentication (HttpServletRequest request , HttpServletResponse response ,
98
101
FilterChain filterChain ) throws ServletException , IOException {
99
102
log .info ("checkAccessTokenAndAuthentication() 호출" );
100
103
jwtTokenProvider .extractAccessToken (request )
101
- .filter (jwtTokenProvider ::isTokenValid )
102
104
.ifPresent (accessToken -> {
103
105
jwtTokenProvider .extractEmail (accessToken )
104
106
.ifPresent (email -> userRepository .findByEmail (email )
@@ -150,17 +152,38 @@ private void handleInvalidTokenException(HttpServletResponse response, InvalidTo
150
152
response .setContentType ("application/json;charset=UTF-8" );
151
153
response .setStatus (HttpServletResponse .SC_UNAUTHORIZED );
152
154
155
+ log .info ("InvalidTokenException 발생" );
156
+
153
157
// ErrorCode에서 정보를 가져옴
154
158
ErrorCode errorCode = ErrorCode .UNAUTHORIZED ;
155
159
156
- // ErrorCode를 사용하여 ApiResponseForm 생성
157
- ApiResponseForm <Void > errorResponse = ApiResponseForm .error (
158
- errorCode .getCode (),
159
- errorCode .getMessage ()
160
- );
161
-
162
- // ObjectMapper를 사용하여 JSON 변환 후 응답에 기록
163
- ObjectMapper objectMapper = new ObjectMapper ();
164
- response .getWriter ().write (objectMapper .writeValueAsString (errorResponse ));
160
+ if (ex instanceof InvalidRefreshTokenException ) {
161
+ ApiResponseForm <Void > errorResponse = ApiResponseForm .refreshTokenInvalid (
162
+ errorCode .getCode (),
163
+ errorCode .getMessage ()
164
+ );
165
+
166
+ // ObjectMapper를 사용하여 JSON 변환 후 응답에 기록
167
+ ObjectMapper objectMapper = new ObjectMapper ();
168
+ response .getWriter ().write (objectMapper .writeValueAsString (errorResponse ));
169
+ } else if (ex instanceof InvalidAccessTokenException ) {
170
+ ApiResponseForm <Void > errorResponse = ApiResponseForm .accessTokenInvalid (
171
+ errorCode .getCode (),
172
+ errorCode .getMessage ()
173
+ );
174
+
175
+ // ObjectMapper를 사용하여 JSON 변환 후 응답에 기록
176
+ ObjectMapper objectMapper = new ObjectMapper ();
177
+ response .getWriter ().write (objectMapper .writeValueAsString (errorResponse ));
178
+ } else if (ex instanceof EmptyAccessTokenException ) {
179
+ ApiResponseForm <Void > errorResponse = ApiResponseForm .accessTokenEmpty (
180
+ errorCode .getCode (),
181
+ errorCode .getMessage ()
182
+ );
183
+
184
+ // ObjectMapper를 사용하여 JSON 변환 후 응답에 기록
185
+ ObjectMapper objectMapper = new ObjectMapper ();
186
+ response .getWriter ().write (objectMapper .writeValueAsString (errorResponse ));
187
+ }
165
188
}
166
189
}
0 commit comments