From c43c795c838cb3bdb120aa7194ed7cdc4928f78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=95=88=EC=A0=95=ED=9B=84?= Date: Thu, 7 Nov 2024 18:28:38 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20logout=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/GlobalExceptionHandler.java | 1 - .../user/handler/CustomLogoutHandler.java | 47 +++++++++++++++++++ .../outbound/config/SecurityConfig.java | 19 +++++++- 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 outbound/src/main/java/com/pocket/outbound/adapter/user/handler/CustomLogoutHandler.java diff --git a/core/src/main/java/com/pocket/core/exception/common/GlobalExceptionHandler.java b/core/src/main/java/com/pocket/core/exception/common/GlobalExceptionHandler.java index f488d54..82f3cf4 100644 --- a/core/src/main/java/com/pocket/core/exception/common/GlobalExceptionHandler.java +++ b/core/src/main/java/com/pocket/core/exception/common/GlobalExceptionHandler.java @@ -21,7 +21,6 @@ public ResponseEntity> handlePhotoBoothNotFound(Phot @ExceptionHandler(SecurityCustomException.class) public ResponseEntity> handleSecurityException(SecurityCustomException ex) { - ApplicationResponse response = new ApplicationResponse<>( new ApplicationResult(Integer.parseInt(ex.getErrorCode().getCode()), ex.getErrorCode().getMessage()), null diff --git a/outbound/src/main/java/com/pocket/outbound/adapter/user/handler/CustomLogoutHandler.java b/outbound/src/main/java/com/pocket/outbound/adapter/user/handler/CustomLogoutHandler.java new file mode 100644 index 0000000..ec3a606 --- /dev/null +++ b/outbound/src/main/java/com/pocket/outbound/adapter/user/handler/CustomLogoutHandler.java @@ -0,0 +1,47 @@ +package com.pocket.outbound.adapter.user.handler; + +import com.pocket.core.exception.jwt.SecurityCustomException; +import com.pocket.core.exception.jwt.SecurityErrorCode; +import com.pocket.core.redis.util.RedisUtil; +import com.pocket.outbound.util.JwtUtil; +import io.jsonwebtoken.ExpiredJwtException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutHandler; + +import java.util.concurrent.TimeUnit; + +@RequiredArgsConstructor +@Slf4j +public class CustomLogoutHandler implements LogoutHandler { + + private final RedisUtil redisUtil; + private final JwtUtil jwtUtil; + + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + try { + log.info("[*] Logout Filter"); + + String accessToken = jwtUtil.resolveAccessToken(request); + + redisUtil.saveAsValue( + accessToken, + "logout", + jwtUtil.getExpTime(accessToken), + TimeUnit.MILLISECONDS + ); + + redisUtil.delete( + jwtUtil.getUsername(accessToken) + "_refresh_token" + ); + + } catch (ExpiredJwtException e) { + log.warn("[*] case : accessToken expired"); + throw new SecurityCustomException(SecurityErrorCode.TOKEN_EXPIRED); + } + } +} diff --git a/outbound/src/main/java/com/pocket/outbound/config/SecurityConfig.java b/outbound/src/main/java/com/pocket/outbound/config/SecurityConfig.java index 83c2084..1a33b7c 100644 --- a/outbound/src/main/java/com/pocket/outbound/config/SecurityConfig.java +++ b/outbound/src/main/java/com/pocket/outbound/config/SecurityConfig.java @@ -2,14 +2,19 @@ import com.pocket.core.exception.jwt.JwtAccessDeniedHandler; import com.pocket.core.exception.jwt.JwtAuthenticationEntryPoint; +import com.pocket.core.redis.util.RedisUtil; +import com.pocket.core.util.HttpResponseUtil; import com.pocket.outbound.adapter.authentication.OAuthLoginFailureHandler; import com.pocket.outbound.adapter.authentication.OAuthLoginSuccessHandler; import com.pocket.outbound.adapter.oauth.KakaoLoginAdapter; +import com.pocket.outbound.adapter.user.handler.CustomLogoutHandler; import com.pocket.outbound.util.JwtFilter; +import com.pocket.outbound.util.JwtUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer; @@ -38,7 +43,7 @@ public class SecurityConfig { private final JwtAccessDeniedHandler jwtAccessDeniedHandler; @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + public SecurityFilterChain securityFilterChain(HttpSecurity http, RedisUtil redisUtil, JwtUtil jwtUtil) throws Exception { http .csrf(AbstractHttpConfigurer::disable) .cors(corsConfigurer -> corsConfigurer.configurationSource(corsConfigurationSource())) @@ -80,6 +85,18 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .authenticationEntryPoint(jwtAuthenticationEntryPoint) .accessDeniedHandler(jwtAccessDeniedHandler)); + http + .logout(logout -> logout + .logoutUrl("/api/v1/users/logout") + .addLogoutHandler(new CustomLogoutHandler(redisUtil, jwtUtil)) + .logoutSuccessHandler((request, response, authentication) + -> HttpResponseUtil.setSuccessResponse( + response, + HttpStatus.OK, + "로그아웃 성공" + )) + ); + return http.build(); }