Skip to content

Commit c696e21

Browse files
committed
feat: 로그아웃 필터 구현
1 parent d58eced commit c696e21

File tree

2 files changed

+121
-3
lines changed

2 files changed

+121
-3
lines changed

src/main/java/com/example/log4u/common/config/SecurityConfig.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
import org.springframework.security.config.http.SessionCreationPolicy;
1313
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter;
1414
import org.springframework.security.web.SecurityFilterChain;
15+
import org.springframework.security.web.authentication.logout.LogoutFilter;
1516
import org.springframework.web.cors.CorsConfiguration;
1617

17-
1818
import com.example.log4u.common.oauth2.handler.OAuth2AuthenticationSuccessHandler;
1919
import com.example.log4u.common.oauth2.jwt.JwtAuthenticationFilter;
20+
import com.example.log4u.common.oauth2.jwt.JwtLogoutFilter;
2021
import com.example.log4u.common.oauth2.jwt.JwtUtil;
22+
import com.example.log4u.common.oauth2.repository.RefreshTokenRepository;
2123
import com.example.log4u.common.oauth2.service.CustomOAuth2UserService;
2224
import com.example.log4u.domain.user.service.UserService;
2325

@@ -31,6 +33,7 @@ public class SecurityConfig {
3133
private final OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
3234
private final CustomOAuth2UserService customOAuth2UserService;
3335
private final UserService userService;
36+
private final RefreshTokenRepository refreshTokenRepository;
3437

3538
@Bean
3639
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws
@@ -43,22 +46,27 @@ public JwtAuthenticationFilter jwtAuthenticationFilter() {
4346
return new JwtAuthenticationFilter(jwtUtil, userService);
4447
}
4548

49+
@Bean
50+
public JwtLogoutFilter jwtLogoutFilter() {
51+
return new JwtLogoutFilter(jwtUtil, refreshTokenRepository);
52+
}
53+
4654
@Bean
4755
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
4856
http
4957
.csrf(AbstractHttpConfigurer::disable) //csrf 비활성화
5058
.formLogin(AbstractHttpConfigurer::disable) //폼 로그인 방식 disable
5159
.httpBasic(AbstractHttpConfigurer::disable); // HTTP Basic 인증 방식 disable
5260

53-
5461
// oauth2 설정
5562
http
5663
.oauth2Login(oauth2 -> oauth2
5764
.userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig
5865
.userService(customOAuth2UserService))
5966
.successHandler(oAuth2AuthenticationSuccessHandler)
6067
)
61-
.addFilterBefore(new JwtAuthenticationFilter(jwtUtil, userService), OAuth2LoginAuthenticationFilter.class);
68+
.addFilterBefore(new JwtAuthenticationFilter(jwtUtil, userService), OAuth2LoginAuthenticationFilter.class)
69+
.addFilterBefore(new JwtLogoutFilter(jwtUtil, refreshTokenRepository), LogoutFilter.class);
6270

6371
//경로별 인가 작업
6472
http
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.example.log4u.common.oauth2.jwt;
2+
3+
import java.io.IOException;
4+
5+
import org.springframework.web.filter.GenericFilterBean;
6+
7+
import com.example.log4u.common.oauth2.repository.RefreshTokenRepository;
8+
9+
import io.jsonwebtoken.ExpiredJwtException;
10+
import jakarta.servlet.FilterChain;
11+
import jakarta.servlet.ServletException;
12+
import jakarta.servlet.ServletRequest;
13+
import jakarta.servlet.ServletResponse;
14+
import jakarta.servlet.http.Cookie;
15+
import jakarta.servlet.http.HttpServletRequest;
16+
import jakarta.servlet.http.HttpServletResponse;
17+
import lombok.RequiredArgsConstructor;
18+
19+
@RequiredArgsConstructor
20+
public class JwtLogoutFilter extends GenericFilterBean {
21+
22+
private final JwtUtil jwtUtil;
23+
private final RefreshTokenRepository refreshTokenRepository;
24+
25+
@Override
26+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws
27+
IOException,
28+
ServletException {
29+
doFilter((HttpServletRequest)request, (HttpServletResponse)response, chain);
30+
}
31+
32+
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws
33+
IOException,
34+
ServletException {
35+
36+
// 경로 확인
37+
String requestUri = request.getRequestURI();
38+
if (!requestUri.matches("^\\/logout$")) {
39+
filterChain.doFilter(request, response);
40+
return;
41+
}
42+
43+
String requestMethod = request.getMethod();
44+
if (!requestMethod.equals("POST")) {
45+
filterChain.doFilter(request, response);
46+
return;
47+
}
48+
49+
// 리프레시 토큰 추출
50+
String refresh = null;
51+
Cookie[] cookies = request.getCookies();
52+
for (Cookie cookie : cookies) {
53+
if (cookie.getName().equals("refresh")) {
54+
refresh = cookie.getValue();
55+
}
56+
}
57+
58+
// 리프레시 토큰 만료 체크
59+
if (refresh == null) {
60+
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
61+
return;
62+
}
63+
64+
// 만료 검사
65+
try {
66+
jwtUtil.isExpired(refresh);
67+
} catch (ExpiredJwtException e) {
68+
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
69+
return;
70+
}
71+
72+
// 토큰이 refresh인지 확인 (발급시 페이로드에 명시)
73+
String tokenType = jwtUtil.getTokenType(refresh);
74+
if (!tokenType.equals("refresh")) {
75+
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
76+
return;
77+
}
78+
79+
//DB에 저장되어 있는지 확인
80+
Boolean isExist = refreshTokenRepository.existsByRefreshToken(refresh);
81+
if (Boolean.FALSE.equals(isExist)) {
82+
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
83+
return;
84+
}
85+
86+
// 로그아웃
87+
logout(response, refresh);
88+
}
89+
90+
public void logout(HttpServletResponse response, String refresh) {
91+
// DB 에서 리프레시 토큰 제거
92+
refreshTokenRepository.deleteByRefreshToken(refresh);
93+
// 쿠키 제거
94+
deleteCookie(response);
95+
}
96+
97+
public void deleteCookie(HttpServletResponse response) {
98+
Cookie access = new Cookie("access", null);
99+
Cookie refresh = new Cookie("refresh", null);
100+
101+
access.setMaxAge(0);
102+
access.setPath("/");
103+
refresh.setMaxAge(0);
104+
refresh.setPath("/");
105+
106+
response.addCookie(access);
107+
response.addCookie(refresh);
108+
response.setStatus(HttpServletResponse.SC_OK);
109+
}
110+
}

0 commit comments

Comments
 (0)