From 59aac1d76cecd711a1ad17460fd1bf89ace5ab82 Mon Sep 17 00:00:00 2001 From: leeyongwoo <95459741+softwareyong@users.noreply.github.com> Date: Wed, 28 Aug 2024 01:41:11 +0900 Subject: [PATCH 1/2] =?UTF-8?q?SCRUM-69=20feat:=20CustomSuccessHandler?= =?UTF-8?q?=EC=97=90=EC=84=9C=20refreshtoken=20db=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../golagola/config/SecurityConfig.java | 22 ++++++---- .../auth/Repository/UserRepository.java | 6 ++- .../domain/auth/entity/UserEntity.java | 4 ++ .../signin}/CustomSuccessHandler.java | 27 +++++++++++-- .../signout/CustomSignOutProcessHandler.java | 40 +++++++++++++++++++ .../golagola/security/jwt/JWTFilter.java | 1 + .../service/CustomOAuth2UserService.java | 23 +++++++---- src/main/resources/application.properties | 2 +- 8 files changed, 106 insertions(+), 19 deletions(-) rename src/main/java/com/kakaoteck/golagola/security/{oauth2 => handler/signin}/CustomSuccessHandler.java (62%) create mode 100644 src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java diff --git a/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java b/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java index 96795c9..7025f61 100644 --- a/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java +++ b/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java @@ -3,17 +3,15 @@ import com.kakaoteck.golagola.security.filter.JwtAuthenticationFilter; import com.kakaoteck.golagola.security.jwt.JWTFilter; import com.kakaoteck.golagola.security.jwt.JWTUtil; -import com.kakaoteck.golagola.security.oauth2.CustomSuccessHandler; +import com.kakaoteck.golagola.security.handler.signin.CustomSuccessHandler; import com.kakaoteck.golagola.service.CustomOAuth2UserService; import jakarta.servlet.http.HttpServletRequest; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; @@ -57,6 +55,9 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { } })); + + + // CSRF 보호 비활성화 http.csrf(AbstractHttpConfigurer::disable); @@ -68,7 +69,17 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { // OAuth2 로그인 설정 http.oauth2Login(oauth2 -> oauth2.userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService)) - .successHandler(customSuccessHandler)); + .successHandler(customSuccessHandler) +// .failureHandler(oAuth2LoginFailureHandler) # 실패핸들러 추가하기 + ); + + // 로그아웃 설정 + http.logout(logout -> logout.logoutUrl("/api/v1/auth/logout") + //.addLogoutHandler(logoutHandler) // 지미꺼 + .addLogoutHandler(logoutHandler) // 코이꺼 + + .deleteCookies("JSESSIONID", "Authorization") + ); // JWT 필터 설정 // http.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); @@ -82,9 +93,6 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { // 세션 설정: STATELESS http.sessionManagement(session -> session.sessionCreationPolicy(STATELESS)); - // 로그아웃 설정 - http.logout(logout -> logout.logoutUrl("/api/v1/auth/logout").addLogoutHandler(logoutHandler)); - return http.build(); } diff --git a/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java b/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java index 73bebfb..a29376c 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java +++ b/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java @@ -3,8 +3,12 @@ import com.kakaoteck.golagola.domain.auth.entity.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.Optional; + public interface UserRepository extends JpaRepository { - UserEntity findByUsername(String username); // username을 전달하여 해당하는 엔티티 가져오기(JPA) +// UserEntity findByUsername(String username); // username을 전달하여 해당하는 엔티티 가져오기(JPA) + + Optional findByUsername(String username); // 차이가 뭔지 공부하기 } diff --git a/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java b/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java index cf39f40..dc94284 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java +++ b/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java @@ -21,6 +21,10 @@ public class UserEntity { private String email; private String role; + // 추가 + private String RefreshToken; // JWT 리프레시 토큰 발급 + private boolean LoginStatus; // 로그인 상태처리 + } diff --git a/src/main/java/com/kakaoteck/golagola/security/oauth2/CustomSuccessHandler.java b/src/main/java/com/kakaoteck/golagola/security/handler/signin/CustomSuccessHandler.java similarity index 62% rename from src/main/java/com/kakaoteck/golagola/security/oauth2/CustomSuccessHandler.java rename to src/main/java/com/kakaoteck/golagola/security/handler/signin/CustomSuccessHandler.java index b8ae13f..4b071f4 100644 --- a/src/main/java/com/kakaoteck/golagola/security/oauth2/CustomSuccessHandler.java +++ b/src/main/java/com/kakaoteck/golagola/security/handler/signin/CustomSuccessHandler.java @@ -1,6 +1,8 @@ -package com.kakaoteck.golagola.security.oauth2; +package com.kakaoteck.golagola.security.handler.signin; +import com.kakaoteck.golagola.domain.auth.Repository.UserRepository; import com.kakaoteck.golagola.domain.auth.dto.CustomOAuth2User; +import com.kakaoteck.golagola.domain.auth.entity.UserEntity; import com.kakaoteck.golagola.security.jwt.JWTUtil; import jakarta.servlet.ServletException; import jakarta.servlet.http.Cookie; @@ -14,13 +16,18 @@ import java.io.IOException; import java.util.Collection; import java.util.Iterator; +import java.util.Optional; @Component public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final JWTUtil jwtUtil; - public CustomSuccessHandler(JWTUtil jwtUtil) { + private final UserRepository userRepository; + + // AutoWired로 대체 가능한가요? + public CustomSuccessHandler(JWTUtil jwtUtil, UserRepository userRepository) { this.jwtUtil = jwtUtil; + this.userRepository = userRepository; } @Override @@ -28,7 +35,6 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo //OAuth2User CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal(); - String username = customUserDetails.getUsername(); Collection authorities = authentication.getAuthorities(); @@ -36,9 +42,24 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo GrantedAuthority auth = iterator.next(); String role = auth.getAuthority(); + // JWT 생성 String token = jwtUtil.createJwt(username, role, 60*60*60L); + // Refresh Token 생성 및 저장 + String refreshToken = jwtUtil.createJwt(username, role, 7*24*60*60L); // 예: 7일간 유효한 리프레시 토큰 + + // UserEntity 업데이트 + Optional userEntityOptional = userRepository.findByUsername(username); + if (userEntityOptional.isPresent()) { + UserEntity userEntity = userEntityOptional.get(); + userEntity.setRefreshToken(refreshToken); + userEntity.setLoginStatus(true); // 로그인 상태를 true로 설정 + userRepository.save(userEntity); // 업데이트된 정보를 저장 + } + + // 쿠키 설정 response.addCookie(createCookie("Authorization", token)); // 쿠키를 넣어준다. + response.addCookie(createCookie("RefreshToken", refreshToken)); // 리프레시 토큰도 쿠키로 추가 response.sendRedirect("http://localhost:8080/"); // 프론트쪽으로 특정 uri로 리다이렉트 } diff --git a/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java b/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java new file mode 100644 index 0000000..1db7cde --- /dev/null +++ b/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java @@ -0,0 +1,40 @@ +//package com.kakaoteck.golagola.security.handler.signout; +// +// +//import jakarta.servlet.http.HttpServletRequest; +//import jakarta.servlet.http.HttpServletResponse; +//import jakarta.transaction.Transactional; +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.security.core.Authentication; +//import org.springframework.security.web.authentication.logout.LogoutHandler; +//import org.springframework.stereotype.Component; +// +//@Component +//@RequiredArgsConstructor +//@Slf4j +//public class CustomSignOutProcessHandler implements LogoutHandler { +//// private final UserRepository userRepository; +//// +//// @Override +//// @Transactional +//// public void logout(HttpServletRequest request, HttpServletResponse response, +//// Authentication authentication) { +//// if (authentication == null) { +//// return; +//// } +//// +//// CustomUserDetails userPrincipal = (CustomUserDetails) authentication.getPrincipal(); +//// +//// userRepository.updateRefreshTokenAndLoginStatus(userPrincipal.getId(), null, false); +//// } +// +// +//} +// +// +// +// +// +// +// diff --git a/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java b/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java index 5c2b340..96cebc2 100644 --- a/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java +++ b/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java @@ -70,6 +70,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // 스프링 시큐리티 인증 토큰 생성 Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2User, null, customOAuth2User.getAuthorities()); + // 세션에 사용자 등록 SecurityContextHolder.getContext().setAuthentication(authToken); diff --git a/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java b/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java index 7bd9ec4..50f2c9e 100644 --- a/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java +++ b/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java @@ -9,6 +9,8 @@ import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; +import java.util.Optional; + // DefaultOAuth2UserService: OAuth2에서 기본적으로 유저를 저장하는 메서드를 가지고 있다. // super로 상속받아서 사용한다. // OAuth2UserRequest: 리소스 서버에서 제공되는 유저정보 @@ -41,15 +43,18 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic //리소스 서버에서 발급 받은 정보로 사용자를 특정할 아이디값을 만듬 String username = oAuth2Response.getProvider() + " " + oAuth2Response.getProviderId(); - UserEntity existData = userRepository.findByUsername(username); + Optional optionalUserEntity = userRepository.findByUsername(username); - if (existData == null) { + // 1. 새로운 유저라면 + if (optionalUserEntity.isEmpty()) { UserEntity userEntity = new UserEntity(); - userEntity.setUsername(username); - userEntity.setEmail(oAuth2Response.getEmail()); - userEntity.setName(oAuth2Response.getName()); - userEntity.setRole("ROLE_USER"); + userEntity.setUsername(username); // ex) kakao 3664463254 + userEntity.setEmail(oAuth2Response.getEmail()); // ex) tiger1650@naver.com + userEntity.setName(oAuth2Response.getName()); // ex) 이용우 + userEntity.setRole("ROLE_USER"); // ex) ROLE_USER + + // 리프레시 토큰 넣기 userRepository.save(userEntity); @@ -59,7 +64,11 @@ public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2Authentic userDTO.setRole("ROLE_USER"); return new CustomOAuth2User(userDTO); - } else { + } + + // 2. 기존 유러라면 + else { + UserEntity existData = optionalUserEntity.get(); existData.setEmail(oAuth2Response.getEmail()); existData.setName(oAuth2Response.getName()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index bec2749..7095e06 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -4,7 +4,7 @@ spring.application.name=golagola spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/golagola?useSSL=false&useUnicode=true&serverTimezone=Asia/Seoul&allowPublicKeyRetrieval=true spring.datasource.username=root -spring.datasource.password=8253 +spring.datasource.password=00000000 spring.jpa.hibernate.ddl-auto=create spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl From d0e63a727b21c9e5b4987e55fe98018df49bb33d Mon Sep 17 00:00:00 2001 From: leeyongwoo <95459741+softwareyong@users.noreply.github.com> Date: Thu, 29 Aug 2024 14:36:44 +0900 Subject: [PATCH 2/2] =?UTF-8?q?SCRUM-69=20fix:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=ED=95=84=ED=84=B0=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../golagola/config/SecurityConfig.java | 22 +++-- .../auth/Repository/UserRepository.java | 9 ++ .../domain/auth/dto/CustomOAuth2User.java | 4 + .../golagola/domain/auth/dto/UserDTO.java | 4 + .../domain/auth/entity/UserEntity.java | 4 +- .../signout/CustomSignOutProcessHandler.java | 87 ++++++++++--------- .../golagola/security/jwt/JWTFilter.java | 19 +++- .../service/CustomOAuth2UserService.java | 1 - 8 files changed, 92 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java b/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java index 7025f61..c6213d6 100644 --- a/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java +++ b/src/main/java/com/kakaoteck/golagola/config/SecurityConfig.java @@ -1,6 +1,7 @@ package com.kakaoteck.golagola.config; import com.kakaoteck.golagola.security.filter.JwtAuthenticationFilter; +import com.kakaoteck.golagola.security.handler.signout.CustomSignOutProcessHandler; import com.kakaoteck.golagola.security.jwt.JWTFilter; import com.kakaoteck.golagola.security.jwt.JWTUtil; import com.kakaoteck.golagola.security.handler.signin.CustomSuccessHandler; @@ -12,6 +13,8 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutFilter; import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; @@ -34,9 +37,7 @@ public class SecurityConfig { private final CustomOAuth2UserService customOAuth2UserService; private final CustomSuccessHandler customSuccessHandler; private final JWTUtil jwtUtil; - private final JwtAuthenticationFilter jwtAuthFilter; - private final AuthenticationProvider authenticationProvider; - private final LogoutHandler logoutHandler; + private final CustomSignOutProcessHandler customSignOutProcessHandler; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -55,9 +56,6 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { } })); - - - // CSRF 보호 비활성화 http.csrf(AbstractHttpConfigurer::disable); @@ -76,14 +74,14 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { // 로그아웃 설정 http.logout(logout -> logout.logoutUrl("/api/v1/auth/logout") //.addLogoutHandler(logoutHandler) // 지미꺼 - .addLogoutHandler(logoutHandler) // 코이꺼 - - .deleteCookies("JSESSIONID", "Authorization") + .addLogoutHandler(customSignOutProcessHandler) // 코이꺼 + .deleteCookies("JSESSIONID", "Authorization", "RefreshToken") ); // JWT 필터 설정 -// http.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); - http.addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); + http.addFilterBefore(new JWTFilter(jwtUtil), LogoutFilter.class); // 로그아웃 필터전에 jwt필터실행 + http.addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class); +// http.addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); // 경로별 인가 작업 http.authorizeHttpRequests(auth -> auth @@ -97,7 +95,7 @@ public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { } private static final String[] WHITE_LIST_URL = { - "/api/v1/auth/**", +// "/api/v1/auth/**", "/v2/api-docs", "/v3/api-docs", "/v3/api-docs/**", diff --git a/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java b/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java index a29376c..146da2f 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java +++ b/src/main/java/com/kakaoteck/golagola/domain/auth/Repository/UserRepository.java @@ -1,7 +1,10 @@ package com.kakaoteck.golagola.domain.auth.Repository; import com.kakaoteck.golagola.domain.auth.entity.UserEntity; +import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import java.util.Optional; @@ -9,6 +12,12 @@ public interface UserRepository extends JpaRepository { // UserEntity findByUsername(String username); // username을 전달하여 해당하는 엔티티 가져오기(JPA) Optional findByUsername(String username); // 차이가 뭔지 공부하기 + + @Modifying + @Query("UPDATE UserEntity u SET u.refreshToken = :refreshToken, u.loginStatus = :loginStatus WHERE u.username = :username") + void updateRefreshTokenAndLoginStatus(@Param("userName") String username, + @Param("refreshToken") String refreshToken, + @Param("loginStatus") boolean loginStatus); } diff --git a/src/main/java/com/kakaoteck/golagola/domain/auth/dto/CustomOAuth2User.java b/src/main/java/com/kakaoteck/golagola/domain/auth/dto/CustomOAuth2User.java index 7490cab..0747c8d 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/auth/dto/CustomOAuth2User.java +++ b/src/main/java/com/kakaoteck/golagola/domain/auth/dto/CustomOAuth2User.java @@ -46,4 +46,8 @@ public String getUsername() { return userDTO.getUsername(); } + public Long getId() { // id 값을 반환하는 메서드 추가 + return userDTO.getId(); + } + } diff --git a/src/main/java/com/kakaoteck/golagola/domain/auth/dto/UserDTO.java b/src/main/java/com/kakaoteck/golagola/domain/auth/dto/UserDTO.java index c5b7ca5..53ae51d 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/auth/dto/UserDTO.java +++ b/src/main/java/com/kakaoteck/golagola/domain/auth/dto/UserDTO.java @@ -7,7 +7,11 @@ @Setter public class UserDTO { + private Long id; // 엔티티의 id 추가 private String role; private String name; private String username; + private String email; // 엔티티의 email 추가 + private String refreshToken; // 엔티티의 refreshToken 추가 + private boolean loginStatus; // 엔티티의 loginStatus 추가 } diff --git a/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java b/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java index dc94284..f460c3d 100644 --- a/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java +++ b/src/main/java/com/kakaoteck/golagola/domain/auth/entity/UserEntity.java @@ -22,8 +22,8 @@ public class UserEntity { private String role; // 추가 - private String RefreshToken; // JWT 리프레시 토큰 발급 - private boolean LoginStatus; // 로그인 상태처리 + private String refreshToken; // JWT 리프레시 토큰 발급 + private boolean loginStatus; // 로그인 상태처리 diff --git a/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java b/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java index 1db7cde..3d531a2 100644 --- a/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java +++ b/src/main/java/com/kakaoteck/golagola/security/handler/signout/CustomSignOutProcessHandler.java @@ -1,40 +1,47 @@ -//package com.kakaoteck.golagola.security.handler.signout; -// -// -//import jakarta.servlet.http.HttpServletRequest; -//import jakarta.servlet.http.HttpServletResponse; -//import jakarta.transaction.Transactional; -//import lombok.RequiredArgsConstructor; -//import lombok.extern.slf4j.Slf4j; -//import org.springframework.security.core.Authentication; -//import org.springframework.security.web.authentication.logout.LogoutHandler; -//import org.springframework.stereotype.Component; -// -//@Component -//@RequiredArgsConstructor -//@Slf4j -//public class CustomSignOutProcessHandler implements LogoutHandler { -//// private final UserRepository userRepository; -//// -//// @Override -//// @Transactional -//// public void logout(HttpServletRequest request, HttpServletResponse response, -//// Authentication authentication) { -//// if (authentication == null) { -//// return; -//// } -//// -//// CustomUserDetails userPrincipal = (CustomUserDetails) authentication.getPrincipal(); -//// -//// userRepository.updateRefreshTokenAndLoginStatus(userPrincipal.getId(), null, false); -//// } -// -// -//} -// -// -// -// -// -// -// +package com.kakaoteck.golagola.security.handler.signout; + + +import com.kakaoteck.golagola.domain.auth.Repository.UserRepository; +import com.kakaoteck.golagola.domain.auth.dto.CustomOAuth2User; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutHandler; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class CustomSignOutProcessHandler implements LogoutHandler { + private final UserRepository userRepository; + + @Override + @Transactional + public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + if (authentication == null) { + return; + } + + // 1. 테리코드 +// CustomUserDetails userPrincipal = (CustomUserDetails) authentication.getPrincipal(); +// userRepository.updateRefreshTokenAndLoginStatus(userPrincipal.getId(), null, false); + + // 2. 용우코드 + CustomOAuth2User userPrincipal = (CustomOAuth2User) authentication.getPrincipal(); // CustomOAuth2User 사용 + System.out.println("로그아웃 정보 확인"+ userPrincipal + userPrincipal.getUsername()); + userRepository.updateRefreshTokenAndLoginStatus(userPrincipal.getUsername(), null, false); // UserEntity에서 해당 유저를 찾아서 리프레시 토큰과 로그인 상태를 업데이트 + + } + + +} + + + + + + + diff --git a/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java b/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java index 96cebc2..8d3b6d5 100644 --- a/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java +++ b/src/main/java/com/kakaoteck/golagola/security/jwt/JWTFilter.java @@ -25,6 +25,19 @@ public JWTFilter(JWTUtil jwtUtil) { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // jwt 기간 만료시, 무한 재로그인 방지 로직 + String requestUri = request.getRequestURI(); + if (requestUri.matches("^\\/login(?:\\/.*)?$")) { + + filterChain.doFilter(request, response); + return; + } + if (requestUri.matches("^\\/oauth2(?:\\/.*)?$")) { + + filterChain.doFilter(request, response); + return; + } + // cookie들을 불러온 뒤 Authorization Key에 담긴 쿠키를 찾음 String authorization = null; Cookie[] cookies = request.getCookies(); @@ -38,7 +51,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } } } - // Authorization 헤더 검증 if (authorization == null) { System.out.println("token null"); @@ -59,6 +71,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // 토큰에서 username과 role 획득 String username = jwtUtil.getUsername(token); String role = jwtUtil.getRole(token); + System.out.println("jwtfilter jwt확인: " + username + role); // userDTO를 생성하여 값 set UserDTO userDTO = new UserDTO(); @@ -68,13 +81,13 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse // UserDetails에 회원 정보 객체 담기 CustomOAuth2User customOAuth2User = new CustomOAuth2User(userDTO); - // 스프링 시큐리티 인증 토큰 생성 + // 스프링 시큐리티 인증 토큰 생성, 스프링 시큐리티에서 세션을 생성해가지고 토큰을 등록하고 있음. Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2User, null, customOAuth2User.getAuthorities()); // 세션에 사용자 등록 SecurityContextHolder.getContext().setAuthentication(authToken); - filterChain.doFilter(request, response); + filterChain.doFilter(request, response); // jwtfilter작업을 다 했기 때문에 다음 필터에게 작업을 넘긴다는 doFilter작업을 진행해주시면 됩니다. } } diff --git a/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java b/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java index 50f2c9e..c57f6a8 100644 --- a/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java +++ b/src/main/java/com/kakaoteck/golagola/service/CustomOAuth2UserService.java @@ -16,7 +16,6 @@ // OAuth2UserRequest: 리소스 서버에서 제공되는 유저정보 @Service public class CustomOAuth2UserService extends DefaultOAuth2UserService { - private final UserRepository userRepository; public CustomOAuth2UserService(UserRepository userRepository) {