로그아웃 기능
로그아웃 기능을 통해 추가적인 JWT 탈취 시간을 줄일 수 있다.
- 로그아웃 버튼 클릭 시
- 프론트엔드 측 : 로컬 스토리지에 존재하는 Access 토큰 삭제 및 서버 측 로그아웃 경로로 Refresh 토큰 전송
- 백엔드 측 : 로그아웃 로직을 추가하여 Refresh 토큰을 받아 쿠키 초기화 후 Refresh DB에서 해당 Refresh 토큰 삭제 (모든 계정에서 로그아웃 구현 시 username 기반으로 모든 Refresh 토큰 삭제)
백엔드에서 로그아웃 수행 작업
- DB에 저장하고 있는 Refresh 토큰 삭제
- Refresh 토큰 쿠키 null로 변경
스프링 시큐리티에서의 로그아웃 구현의 위치
일반적으로 스프링 시큐리티 의존성을 프로젝트에 추가했을 경우 기본 로그아웃 기능이 활성화 된다. 해당 로그아웃을 수행하는 클래스의 위치는 필터 단이다.
org.springframework.security.web.session.DisableEncodeUrlFilter@404db674,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@50f097b5,
org.springframework.security.web.context.SecurityContextHolderFilter@6fc6deb7,
org.springframework.security.web.header.HeaderWriterFilter@6f76c2cc,
org.springframework.security.web.csrf.CsrfFilter@c29fe36,
org.springframework.security.web.authentication.logout.LogoutFilter@ef60710,
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter@7c2dfa2,
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter@4397a639,
org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter@7add838c,
org.springframework.security.web.authentication.www.BasicAuthenticationFilter@5cc9d3d0,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@7da39774,
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@32b0876c,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3662bdff,
org.springframework.security.web.access.ExceptionTranslationFilter@77681ce4,
org.springframework.security.web.access.intercept.AuthorizationFilter@169268a7]
따라서 우리의 커스텀 필터 또한 시큐리티 필터 단에 구현할 예정이다.
로그아웃 필터 구현
public class CustomLogoutFilter extends GenericFilterBean {
private final JWTUtil jwtUtil;
private final RefreshRepository refreshRepository;
public CustomLogoutFilter(JWTUtil jwtUtil, RefreshRepository refreshRepository) {
this.jwtUtil = jwtUtil;
this.refreshRepository = refreshRepository;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
}
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//path and method verify
String requestUri = request.getRequestURI();
if (!requestUri.matches("^\\/logout$")) {
filterChain.doFilter(request, response);
return;
}
String requestMethod = request.getMethod();
if (!requestMethod.equals("POST")) {
filterChain.doFilter(request, response);
return;
}
//get refresh token
String refresh = null;
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies) {
if (cookie.getName().equals("refresh")) {
refresh = cookie.getValue();
}
}
//refresh null check
if (refresh == null) {
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
//expired check
try {
jwtUtil.isExpired(refresh);
} catch (ExpiredJwtException e) {
//response status code
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
// 토큰이 refresh인지 확인 (발급시 페이로드에 명시)
String category = jwtUtil.getCategory(refresh);
if (!category.equals("refresh")) {
//response status code
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
//DB에 저장되어 있는지 확인
Boolean isExist = refreshRepository.existsByRefresh(refresh);
if (!isExist) {
//response status code
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
//로그아웃 진행
//Refresh 토큰 DB에서 제거
refreshRepository.deleteByRefresh(refresh);
//Refresh 토큰 Cookie 값 0
Cookie cookie = new Cookie("refresh", null);
cookie.setMaxAge(0);
cookie.setPath("/");
response.addCookie(cookie);
response.setStatus(HttpServletResponse.SC_OK);
}
}
SecurityConfig 등록
http
.addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class);
'Spring Security > JWT' 카테고리의 다른 글
REDBOX(헌혈증 기부 시스템) - JWT 정리 (0) | 2025.01.16 |
---|---|
스프링 JWT 심화 8 : Refresh 토큰 서버 측 저장 (0) | 2024.12.22 |
스프링 JWT 심화 7 : Refresh Rotate (0) | 2024.12.22 |
스프링 JWT 심화 6 : Refresh로 Access 토큰 재발급 (0) | 2024.12.22 |
스프링 JWT 심화 5 : Access 토큰 필터 : JWTFilter (0) | 2024.12.22 |