From 74afe9765ce4b15d18d7df595479e5405c44c1e7 Mon Sep 17 00:00:00 2001 From: heejjinkim <06.hjhj.12@gmail.com> Date: Tue, 17 Sep 2024 23:57:08 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feature:=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit security 기본 로그아웃 사용 저장된 refresh token 삭제하는 핸들러 추가 related to: #11 --- .../global/config/WebSecurityConfig.java | 28 +++++++++---------- .../global/handler/CustomLogoutHandler.java | 22 +++++++++++++++ .../handler/CustomLogoutSuccessHandler.java | 19 +++++++++++++ 3 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/_119/wepro/global/handler/CustomLogoutHandler.java create mode 100644 src/main/java/com/_119/wepro/global/handler/CustomLogoutSuccessHandler.java diff --git a/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java b/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java index 1a1d83a..0f82601 100644 --- a/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java +++ b/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java @@ -4,26 +4,20 @@ import com._119.wepro.global.filter.JwtTokenExceptionFilter; import com._119.wepro.global.filter.JwtTokenFilter; +import com._119.wepro.global.handler.CustomLogoutHandler; +import com._119.wepro.global.handler.CustomLogoutSuccessHandler; import com._119.wepro.global.security.CustomOidcAuthenticationSuccessHandler; -import com._119.wepro.global.security.CustomOidcUserService; import com._119.wepro.global.security.JwtTokenProvider; import lombok.RequiredArgsConstructor; -import org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.config.Customizer; 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; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.AuthenticationFailureHandler; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutFilter; @Configuration @EnableWebSecurity @@ -40,7 +34,8 @@ public class WebSecurityConfig { public WebSecurityCustomizer webSecurityCustomizer() { // 정적 리소스 제외 return web -> web.ignoring() .requestMatchers("/css/**", "/images/**", "/js/**", "/lib/**") - .requestMatchers("/swagger-ui-custom.html", "/api-docs/**", "/swagger-ui/**", "swagger-ui.html", "/v3/api-docs/**") + .requestMatchers("/swagger-ui-custom.html", "/api-docs/**", "/swagger-ui/**", + "swagger-ui.html", "/v3/api-docs/**") .requestMatchers("/error", "/favicon.ico"); } @@ -62,13 +57,18 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { c.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .httpBasic(withDefaults()) .oauth2Login(oauth2Login -> oauth2Login - .loginPage("http://localhost:3000/") - .failureHandler(customAuthenticationFailureHandler) - .successHandler(customOidcAuthenticationSuccessHandler()) +// .loginPage("http://localhost:3000/") + .failureHandler(customAuthenticationFailureHandler) + .successHandler(customOidcAuthenticationSuccessHandler()) + ) + .logout(logoutConfigurer -> logoutConfigurer + .logoutUrl("/logout") + .addLogoutHandler(new CustomLogoutHandler(jwtTokenProvider)) + .logoutSuccessHandler(new CustomLogoutSuccessHandler()) ); http.addFilterBefore(new JwtTokenFilter(jwtTokenProvider), - UsernamePasswordAuthenticationFilter.class) + LogoutFilter.class) .addFilterBefore(new JwtTokenExceptionFilter(), JwtTokenFilter.class); return http.build(); } diff --git a/src/main/java/com/_119/wepro/global/handler/CustomLogoutHandler.java b/src/main/java/com/_119/wepro/global/handler/CustomLogoutHandler.java new file mode 100644 index 0000000..df2f034 --- /dev/null +++ b/src/main/java/com/_119/wepro/global/handler/CustomLogoutHandler.java @@ -0,0 +1,22 @@ +package com._119.wepro.global.handler; + +import com._119.wepro.global.security.JwtTokenProvider; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutHandler; + +@RequiredArgsConstructor +public class CustomLogoutHandler implements LogoutHandler { + + private final JwtTokenProvider jwtTokenProvider; + + @Override + public void logout(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) { + + String providerId = authentication.getName(); + jwtTokenProvider.deleteInvalidRefreshToken(providerId); + } +} diff --git a/src/main/java/com/_119/wepro/global/handler/CustomLogoutSuccessHandler.java b/src/main/java/com/_119/wepro/global/handler/CustomLogoutSuccessHandler.java new file mode 100644 index 0000000..3634f25 --- /dev/null +++ b/src/main/java/com/_119/wepro/global/handler/CustomLogoutSuccessHandler.java @@ -0,0 +1,19 @@ +package com._119.wepro.global.handler; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; + +public class CustomLogoutSuccessHandler implements LogoutSuccessHandler { + + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, + Authentication authentication) throws IOException, ServletException { + + response.setStatus(HttpServletResponse.SC_OK); + response.getWriter().flush(); + } +} From b96fba0a886c4739f3d5b95e601de4b418c02fcf Mon Sep 17 00:00:00 2001 From: heejjinkim <06.hjhj.12@gmail.com> Date: Wed, 18 Sep 2024 01:25:25 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feature:=20=ED=86=A0=ED=81=B0=20=EC=9E=AC?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit related to: #11 --- .../global/config/WebSecurityConfig.java | 3 +- .../global/security/JwtTokenProvider.java | 1 - .../domain/repository/MemberRepository.java | 5 ++ .../member/presentation/memberController.java | 18 +++++ .../wepro/member/service/ReissueService.java | 76 +++++++++++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/_119/wepro/member/service/ReissueService.java diff --git a/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java b/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java index 0f82601..c885d32 100644 --- a/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java +++ b/src/main/java/com/_119/wepro/global/config/WebSecurityConfig.java @@ -36,7 +36,8 @@ public WebSecurityCustomizer webSecurityCustomizer() { // 정적 리소스 제 .requestMatchers("/css/**", "/images/**", "/js/**", "/lib/**") .requestMatchers("/swagger-ui-custom.html", "/api-docs/**", "/swagger-ui/**", "swagger-ui.html", "/v3/api-docs/**") - .requestMatchers("/error", "/favicon.ico"); + .requestMatchers("/error", "/favicon.ico") + .requestMatchers("/members/reissue"); } @Bean diff --git a/src/main/java/com/_119/wepro/global/security/JwtTokenProvider.java b/src/main/java/com/_119/wepro/global/security/JwtTokenProvider.java index a392dd3..ebc22d7 100644 --- a/src/main/java/com/_119/wepro/global/security/JwtTokenProvider.java +++ b/src/main/java/com/_119/wepro/global/security/JwtTokenProvider.java @@ -48,7 +48,6 @@ public TokenInfo generateToken(String providerId, MemberRole memberRole) { String accessToken = generateAccessToken(providerId, memberRole); String refreshToken = generateRefreshToken(); - // TODO: access 블랙리스트? deleteInvalidRefreshToken(providerId); redisUtil.setData(providerId, refreshToken); diff --git a/src/main/java/com/_119/wepro/member/domain/repository/MemberRepository.java b/src/main/java/com/_119/wepro/member/domain/repository/MemberRepository.java index b424d91..09875fd 100644 --- a/src/main/java/com/_119/wepro/member/domain/repository/MemberRepository.java +++ b/src/main/java/com/_119/wepro/member/domain/repository/MemberRepository.java @@ -2,13 +2,18 @@ import com._119.wepro.member.domain.Member; import com._119.wepro.member.domain.OauthInfo; +import io.lettuce.core.dynamic.annotation.Param; import java.security.Provider; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @Repository public interface MemberRepository extends JpaRepository { Optional findByOauthInfo(OauthInfo oauthInfo); + + @Query("SELECT m FROM Member m WHERE m.oauthInfo.providerId = :providerId") + Optional findByProviderId(@Param("providerId") String providerId); } diff --git a/src/main/java/com/_119/wepro/member/presentation/memberController.java b/src/main/java/com/_119/wepro/member/presentation/memberController.java index 3d108f4..4d0145b 100644 --- a/src/main/java/com/_119/wepro/member/presentation/memberController.java +++ b/src/main/java/com/_119/wepro/member/presentation/memberController.java @@ -1,9 +1,17 @@ package com._119.wepro.member.presentation; +import static com._119.wepro.global.security.constant.SecurityConstants.ACCESS_TOKEN_HEADER; +import static com._119.wepro.global.security.constant.SecurityConstants.REFRESH_TOKEN_HEADER; + import com._119.wepro.global.util.SecurityUtil; +import com._119.wepro.member.service.ReissueService; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -13,9 +21,19 @@ public class memberController { private final SecurityUtil securityUtil; + private final ReissueService reissueService; @GetMapping("/me") public ResponseEntity index() { return ResponseEntity.ok(securityUtil.getCurrentMemberId()); } + + @PostMapping("/reissue") + @Operation(summary = "access token 재발급") + public ResponseEntity refresh( + @RequestHeader(REFRESH_TOKEN_HEADER) String refreshToken, + @RequestHeader(ACCESS_TOKEN_HEADER) String accessToken, HttpServletResponse response) { + reissueService.reissue(refreshToken, accessToken, response); + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/com/_119/wepro/member/service/ReissueService.java b/src/main/java/com/_119/wepro/member/service/ReissueService.java new file mode 100644 index 0000000..0596771 --- /dev/null +++ b/src/main/java/com/_119/wepro/member/service/ReissueService.java @@ -0,0 +1,76 @@ +package com._119.wepro.member.service; + +import static com._119.wepro.global.exception.errorcode.CommonErrorCode.EXPIRED_TOKEN; +import static com._119.wepro.global.exception.errorcode.CommonErrorCode.INVALID_TOKEN; +import static com._119.wepro.global.exception.errorcode.CommonErrorCode.NOT_EXIST_BEARER_SUFFIX; +import static com._119.wepro.global.exception.errorcode.CommonErrorCode.REFRESH_DENIED; +import static com._119.wepro.global.security.constant.SecurityConstants.ACCESS_TOKEN_HEADER; +import static com._119.wepro.global.security.constant.SecurityConstants.GRANT_TYPE; +import static com._119.wepro.global.security.constant.SecurityConstants.REFRESH_TOKEN_HEADER; + +import com._119.wepro.global.dto.TokenInfo; +import com._119.wepro.global.exception.RestApiException; +import com._119.wepro.global.exception.errorcode.UserErrorCode; +import com._119.wepro.global.security.JwtTokenProvider; +import com._119.wepro.member.domain.Member; +import com._119.wepro.member.domain.repository.MemberRepository; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ReissueService { + + private final JwtTokenProvider jwtTokenProvider; + private final MemberRepository memberRepository; + + public void reissue(String refreshToken, String accessToken, HttpServletResponse response) { + refreshToken = extractToken(refreshToken); + accessToken = extractToken(accessToken); + + validateAccessTokenExpired(accessToken); + String providerId = jwtTokenProvider.parseExpiredToken(accessToken).getSubject(); + + validateRefreshToken(refreshToken, providerId); + + Member member = memberRepository.findByProviderId(providerId) + .orElseThrow(() -> new RestApiException(UserErrorCode.USER_NOT_FOUND)); + + TokenInfo newTokenInfo = jwtTokenProvider.generateToken(providerId, member.getRole()); + setTokenPairToResponseHeader(response, newTokenInfo.getAccessToken(), + newTokenInfo.getRefreshToken()); + } + + private String extractToken(String token) { + if (!token.startsWith(GRANT_TYPE)) { + throw new RestApiException(NOT_EXIST_BEARER_SUFFIX); + } + + return token.replace(GRANT_TYPE, ""); + } + + private void validateAccessTokenExpired(String accessToken) { + try { + jwtTokenProvider.validateToken(accessToken); + throw new RestApiException(REFRESH_DENIED); + } catch (RestApiException e) { + if (e.getErrorCode() != EXPIRED_TOKEN) { + throw e; + } + } + } + + private void validateRefreshToken(String refreshToken, String memberId) { + String savedRefreshToken = jwtTokenProvider.getRefreshToken(memberId); + if (!refreshToken.equals(savedRefreshToken)) { + throw new RestApiException(INVALID_TOKEN); + } + } + + private void setTokenPairToResponseHeader( + HttpServletResponse response, String accessToken, String refreshToken) { + response.setHeader(ACCESS_TOKEN_HEADER, GRANT_TYPE + accessToken); + response.setHeader(REFRESH_TOKEN_HEADER, GRANT_TYPE + refreshToken); + } +} From de14cacb360890d8e945b7250de6abfe70b04344 Mon Sep 17 00:00:00 2001 From: heejjinkim <06.hjhj.12@gmail.com> Date: Thu, 26 Sep 2024 10:22:26 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=EC=95=88=20=EC=93=B0=EB=8A=94?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wepro/auth/client/KakaoOauthClient.java | 29 ---- .../wepro/auth/dto/request/AuthRequest.java | 49 ------ .../wepro/auth/dto/response/AuthResponse.java | 16 -- .../auth/dto/response/KakaoTokenResponse.java | 15 -- .../dto/response/OIDCPublicKeyResponse.java | 23 --- .../wepro/auth/dto/response/TokenInfo.java | 12 -- .../auth/jwt/JwtTokenExceptionFilter.java | 50 ------ .../_119/wepro/auth/jwt/JwtTokenFilter.java | 55 ------ .../_119/wepro/auth/jwt/JwtTokenProvider.java | 164 ------------------ .../auth/presentation/AuthController.java | 75 -------- .../_119/wepro/auth/service/AuthService.java | 80 --------- .../_119/wepro/auth/service/KakaoService.java | 73 -------- .../wepro/auth/service/RefreshService.java | 61 ------- .../global/config/FeignClientConfig.java | 10 -- .../wepro/global/config/SecurityConfig.java | 53 ------ .../exception/GlobalExceptionHandler.java | 18 +- .../wepro/member/service/ReissueService.java | 10 +- 17 files changed, 7 insertions(+), 786 deletions(-) delete mode 100644 src/main/java/com/_119/wepro/auth/client/KakaoOauthClient.java delete mode 100644 src/main/java/com/_119/wepro/auth/dto/request/AuthRequest.java delete mode 100644 src/main/java/com/_119/wepro/auth/dto/response/AuthResponse.java delete mode 100644 src/main/java/com/_119/wepro/auth/dto/response/KakaoTokenResponse.java delete mode 100644 src/main/java/com/_119/wepro/auth/dto/response/OIDCPublicKeyResponse.java delete mode 100644 src/main/java/com/_119/wepro/auth/dto/response/TokenInfo.java delete mode 100644 src/main/java/com/_119/wepro/auth/jwt/JwtTokenExceptionFilter.java delete mode 100644 src/main/java/com/_119/wepro/auth/jwt/JwtTokenFilter.java delete mode 100644 src/main/java/com/_119/wepro/auth/jwt/JwtTokenProvider.java delete mode 100644 src/main/java/com/_119/wepro/auth/presentation/AuthController.java delete mode 100644 src/main/java/com/_119/wepro/auth/service/AuthService.java delete mode 100644 src/main/java/com/_119/wepro/auth/service/KakaoService.java delete mode 100644 src/main/java/com/_119/wepro/auth/service/RefreshService.java delete mode 100644 src/main/java/com/_119/wepro/global/config/FeignClientConfig.java delete mode 100644 src/main/java/com/_119/wepro/global/config/SecurityConfig.java diff --git a/src/main/java/com/_119/wepro/auth/client/KakaoOauthClient.java b/src/main/java/com/_119/wepro/auth/client/KakaoOauthClient.java deleted file mode 100644 index 02e779d..0000000 --- a/src/main/java/com/_119/wepro/auth/client/KakaoOauthClient.java +++ /dev/null @@ -1,29 +0,0 @@ -package com._119.wepro.auth.client; - -import com._119.wepro.auth.dto.response.KakaoTokenResponse; -import com._119.wepro.auth.dto.response.OIDCPublicKeyResponse; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; - -@FeignClient( - name = "KakaoOauthClient", - url = "https://kauth.kakao.com" -) -public interface KakaoOauthClient { - - // 만약 클라이언트로부터 code 받을 경우, - @PostMapping( - "/oauth/token?grant_type=authorization_code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&code={CODE}&client_secret={CLIENT_SECRET}") - KakaoTokenResponse kakaoAuth( - @PathVariable("CLIENT_ID") String clientId, - @PathVariable("REDIRECT_URI") String redirectUri, - @PathVariable("CODE") String code, - @PathVariable("CLIENT_SECRET") String client_secret); - - // oidc 공개 키 받아 오기 - 안 쓸 예정 -// @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") // 공개키 자주 요청할 거 같으면, 캐싱하기 - @GetMapping("/.well-known/jwks.json") - OIDCPublicKeyResponse getOIDCPublicKey(); -} \ No newline at end of file diff --git a/src/main/java/com/_119/wepro/auth/dto/request/AuthRequest.java b/src/main/java/com/_119/wepro/auth/dto/request/AuthRequest.java deleted file mode 100644 index f3c6cee..0000000 --- a/src/main/java/com/_119/wepro/auth/dto/request/AuthRequest.java +++ /dev/null @@ -1,49 +0,0 @@ -package com._119.wepro.auth.dto.request; - -import com._119.wepro.global.enums.Provider; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - -public class AuthRequest { - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class SignInRequest { - - @NotNull - @Enumerated(EnumType.STRING) - private Provider provider; - - @NotNull - private String idToken; - } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class RefreshRequest { - @NotNull - private String accessToken; - - @NotNull - private String refreshToken; - } - - @Getter - @Builder - @NoArgsConstructor - @AllArgsConstructor - public static class SignUpRequest { - - @NotNull - private String position; - } -} diff --git a/src/main/java/com/_119/wepro/auth/dto/response/AuthResponse.java b/src/main/java/com/_119/wepro/auth/dto/response/AuthResponse.java deleted file mode 100644 index e6b4bab..0000000 --- a/src/main/java/com/_119/wepro/auth/dto/response/AuthResponse.java +++ /dev/null @@ -1,16 +0,0 @@ -package com._119.wepro.auth.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -public class AuthResponse { - - @Getter - @AllArgsConstructor - public static class SignInResponse { - - private boolean newMember; - private TokenInfo tokenInfo; - } - -} diff --git a/src/main/java/com/_119/wepro/auth/dto/response/KakaoTokenResponse.java b/src/main/java/com/_119/wepro/auth/dto/response/KakaoTokenResponse.java deleted file mode 100644 index f339f5f..0000000 --- a/src/main/java/com/_119/wepro/auth/dto/response/KakaoTokenResponse.java +++ /dev/null @@ -1,15 +0,0 @@ -package com._119.wepro.auth.dto.response; - -import com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -@JsonNaming(SnakeCaseStrategy.class) -public class KakaoTokenResponse { - private String accessToken; - private String refreshToken; - private String idToken; -} diff --git a/src/main/java/com/_119/wepro/auth/dto/response/OIDCPublicKeyResponse.java b/src/main/java/com/_119/wepro/auth/dto/response/OIDCPublicKeyResponse.java deleted file mode 100644 index 5f27996..0000000 --- a/src/main/java/com/_119/wepro/auth/dto/response/OIDCPublicKeyResponse.java +++ /dev/null @@ -1,23 +0,0 @@ -package com._119.wepro.auth.dto.response; - -import java.util.List; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class OIDCPublicKeyResponse { - - private List keys; - - @Getter - @NoArgsConstructor - public static class OIDCPublicKey { - - private String kid; - private String alg; - private String use; - private String n; - private String e; - } -} diff --git a/src/main/java/com/_119/wepro/auth/dto/response/TokenInfo.java b/src/main/java/com/_119/wepro/auth/dto/response/TokenInfo.java deleted file mode 100644 index 8912728..0000000 --- a/src/main/java/com/_119/wepro/auth/dto/response/TokenInfo.java +++ /dev/null @@ -1,12 +0,0 @@ -package com._119.wepro.auth.dto.response; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -@Getter -@AllArgsConstructor -public class TokenInfo { - private String type; - private String accessToken; - private String refreshToken; -} diff --git a/src/main/java/com/_119/wepro/auth/jwt/JwtTokenExceptionFilter.java b/src/main/java/com/_119/wepro/auth/jwt/JwtTokenExceptionFilter.java deleted file mode 100644 index 57a9415..0000000 --- a/src/main/java/com/_119/wepro/auth/jwt/JwtTokenExceptionFilter.java +++ /dev/null @@ -1,50 +0,0 @@ -package com._119.wepro.auth.jwt; - -import com._119.wepro.global.dto.ErrorResponseDto; -import com._119.wepro.global.exception.RestApiException; -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.filter.OncePerRequestFilter; - -@Slf4j -public class JwtTokenExceptionFilter extends OncePerRequestFilter { - - private final ObjectMapper objectMapper = new ObjectMapper(); - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - try { - filterChain.doFilter(request, response); - } catch (RestApiException e) { - logClientIpAndRequestUri(request); - sendErrorResponse(response, e); - } - } - - private void logClientIpAndRequestUri(HttpServletRequest request) { - String clientIp = request.getHeader("X-Forwarded-For"); - if (clientIp == null) { - clientIp = request.getRemoteAddr(); - } - log.error("Invalid token for requestURI: {}, Access from IP: {}", request.getRequestURI(), - clientIp); - } - - private void sendErrorResponse(HttpServletResponse response, RestApiException e) - throws IOException { - ErrorResponseDto errorResponseDto = ErrorResponseDto.builder() - .code(e.getErrorCode().name()) - .message(e.getErrorCode().getMessage()) - .build(); - - response.setStatus(e.getErrorCode().getHttpStatus().value()); - response.setContentType("application/json;charset=UTF-8"); - response.getWriter().write(objectMapper.writeValueAsString(errorResponseDto)); - } -} \ No newline at end of file diff --git a/src/main/java/com/_119/wepro/auth/jwt/JwtTokenFilter.java b/src/main/java/com/_119/wepro/auth/jwt/JwtTokenFilter.java deleted file mode 100644 index 341c3d3..0000000 --- a/src/main/java/com/_119/wepro/auth/jwt/JwtTokenFilter.java +++ /dev/null @@ -1,55 +0,0 @@ -package com._119.wepro.auth.jwt; - -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.NOT_EXIST_BEARER_SUFFIX; - -import com._119.wepro.global.exception.RestApiException; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.OncePerRequestFilter; - -@Slf4j -@RequiredArgsConstructor -public class JwtTokenFilter extends OncePerRequestFilter { - - private final JwtTokenProvider jwtTokenProvider; - private final String accessHeader = "Authorization"; - private final String grantType = "Bearer"; - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - - Optional token = getTokensFromHeader(request, accessHeader); - - token.ifPresent(t -> { - String accessToken = getAccessToken(t); - - Authentication authentication = jwtTokenProvider.getAuthentication(accessToken); - - SecurityContextHolder.getContext().setAuthentication(authentication); - }); - filterChain.doFilter(request, response); - } - - private Optional getTokensFromHeader(HttpServletRequest request, String header) { - return Optional.ofNullable(request.getHeader(header)); - } - - private String getAccessToken(String token) { - String suffix = grantType + " "; - - if (!token.startsWith(suffix)) { - throw new RestApiException(NOT_EXIST_BEARER_SUFFIX); - } - - return token.replace(suffix, ""); - } -} diff --git a/src/main/java/com/_119/wepro/auth/jwt/JwtTokenProvider.java b/src/main/java/com/_119/wepro/auth/jwt/JwtTokenProvider.java deleted file mode 100644 index c95870c..0000000 --- a/src/main/java/com/_119/wepro/auth/jwt/JwtTokenProvider.java +++ /dev/null @@ -1,164 +0,0 @@ -package com._119.wepro.auth.jwt; - -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.EXPIRED_TOKEN; -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.INVALID_TOKEN; - -import com._119.wepro.auth.dto.response.TokenInfo; -import com._119.wepro.global.enums.Role; -import com._119.wepro.global.exception.RestApiException; -import com._119.wepro.global.util.RedisUtil; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.ExpiredJwtException; -import io.jsonwebtoken.JwtException; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.MalformedJwtException; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.UnsupportedJwtException; -import io.jsonwebtoken.security.Keys; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import javax.crypto.SecretKey; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.stereotype.Component; -import org.springframework.util.StringUtils; - -@Component -public class JwtTokenProvider { - - private static final long ACCESS_TOKEN_DURATION = 1000 * 60 * 60L * 24; // 1일 - private static final long REFRESH_TOKEN_DURATION = 1000 * 60 * 60L * 24 * 7; // 7일 - private static final String AUTHORITIES_KEY = "auth"; - private final RedisUtil redisUtil; - private SecretKey secretKey; - - public JwtTokenProvider(@Value("${jwt.secret}") String key, RedisUtil redisUtil) { - this.redisUtil = redisUtil; - byte[] keyBytes = key.getBytes(); - this.secretKey = Keys.hmacShaKeyFor(keyBytes); - } - - public TokenInfo generateToken(String providerId, Role memberRole) { - String accessToken = generateAccessToken(providerId, memberRole); - String refreshToken = generateRefreshToken(); - - deleteInvalidRefreshToken(providerId); - redisUtil.setData(providerId, refreshToken); - - return new TokenInfo("Bearer", accessToken, refreshToken); - } - - public boolean validateToken(String token) { - if (!StringUtils.hasText(token)) { - return false; - } - - Claims claims = parseClaims(token); - return claims.getExpiration().after(new Date()); - } - - - public Authentication getAuthentication(String accessToken) { - Claims claims = parseClaims(accessToken); - - if (claims.get(AUTHORITIES_KEY) == null) { - throw new RestApiException(INVALID_TOKEN); - } - List authority = getAuthorities(claims); - validateAuthorityValue(authority); - - UserDetails principal = new User(claims.getSubject(), "", authority); - return new UsernamePasswordAuthenticationToken(principal, "", authority); - } - - private void validateAuthorityValue(List authority) { - if (authority.size() != 1 - || !isValidAuthority(authority.get(0))) { - throw new RestApiException(INVALID_TOKEN); - } - } - - private boolean isValidAuthority(SimpleGrantedAuthority authority) { - for (Role role : Role.values()) { - if (role.name().equals(authority.getAuthority())) { - return true; - } - } - return false; - } - - private Claims parseClaims(String accessToken) { - try { - return Jwts.parserBuilder() - .setSigningKey(secretKey) - .build() - .parseClaimsJws(accessToken) - .getBody(); - } catch (SecurityException | MalformedJwtException e) { - throw new RestApiException(INVALID_TOKEN); - } catch (ExpiredJwtException e) { - throw new RestApiException(EXPIRED_TOKEN); - } catch (UnsupportedJwtException e) { - throw new RestApiException(INVALID_TOKEN); - } catch (IllegalArgumentException e) { - throw new RestApiException(INVALID_TOKEN); - } catch (JwtException e) { - throw new RestApiException(INVALID_TOKEN); - } - } - - private String generateAccessToken(String providerId, Role memberRole) { - Date now = new Date(); - Date expiredDate = new Date(now.getTime() + ACCESS_TOKEN_DURATION); - - return Jwts.builder() - .setSubject(providerId) - .claim(AUTHORITIES_KEY, memberRole.name()) - .setIssuedAt(now) - .setExpiration(expiredDate) - .signWith(secretKey, SignatureAlgorithm.HS256) - .compact(); - } - - private String generateRefreshToken() { - Date now = new Date(); - Date expiredDate = new Date(now.getTime() + REFRESH_TOKEN_DURATION); - - return Jwts.builder() - .setExpiration(expiredDate) - .signWith(secretKey, SignatureAlgorithm.HS256) - .compact(); - } - - private List getAuthorities(Claims claims) { - return Collections.singletonList(new SimpleGrantedAuthority( - claims.get(AUTHORITIES_KEY).toString())); - } - - public String getRefreshToken(String provierId) { - return redisUtil.getData(provierId); - } - - public void deleteInvalidRefreshToken(String provierId) { - redisUtil.deleteData(provierId); - } - - public Claims parseExpiredToken(String token) { - try { - return Jwts.parserBuilder() - .setSigningKey(secretKey) - .build() - .parseClaimsJws(token) - .getBody(); - } catch (ExpiredJwtException e) { - return e.getClaims(); - } catch (JwtException e) { - throw new RestApiException(INVALID_TOKEN); - } - } -} diff --git a/src/main/java/com/_119/wepro/auth/presentation/AuthController.java b/src/main/java/com/_119/wepro/auth/presentation/AuthController.java deleted file mode 100644 index f9f8c8f..0000000 --- a/src/main/java/com/_119/wepro/auth/presentation/AuthController.java +++ /dev/null @@ -1,75 +0,0 @@ -package com._119.wepro.auth.presentation; - -import com._119.wepro.auth.dto.response.AuthResponse.SignInResponse; -import com._119.wepro.auth.dto.response.TokenInfo; -import com._119.wepro.auth.service.KakaoService; -import com._119.wepro.auth.service.RefreshService; -import com._119.wepro.auth.service.AuthService; -import com._119.wepro.auth.dto.request.AuthRequest.*; -import io.swagger.v3.oas.annotations.Operation; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.view.RedirectView; - -@Slf4j -@RequiredArgsConstructor -@RestController -public class AuthController { - - private final KakaoService kakaoService; - private final AuthService authService; - private final RefreshService refreshService; - - @PostMapping("/login") - @Operation(summary = "Kakao idToken 받아 소셜 로그인") - public ResponseEntity signIn( - @RequestBody @Valid SignInRequest request) { - return ResponseEntity.ok(authService.signIn(request)); - } - - @PostMapping("/refresh") - @Operation(summary = "access token 재발급") - public ResponseEntity refresh( - @RequestBody @Valid RefreshRequest request) { - return ResponseEntity.ok(refreshService.refresh(request)); - } - - @PostMapping("/logout") - @Operation(summary = "로그아웃") - public ResponseEntity logout(Authentication authentication){ - authService.logOut(authentication.getName()); - return ResponseEntity.ok().build(); - } - - @PostMapping("/signup") - @Operation(summary = "직군 정보 받아 최종 회원가입") - public ResponseEntity register( - @RequestBody @Valid SignUpRequest request) { - return ResponseEntity.ok().build(); - } - - @GetMapping("/auth/kakao") - @Operation(summary = "Kakao Web 소셜 로그인 용 api, 백엔드용") - public RedirectView kakaoLogin() { - return new RedirectView(kakaoService.generateKakaoRedirectUrl()); - } - - @GetMapping("/login/oauth2/code/kakao") - @Operation(summary = "카카오 code 받는 api, 백엔드용") - public SignInResponse handleKakaoCallback(@RequestParam String code) { - return kakaoService.handleKakaoCallback(code); - } - - @GetMapping("/test") - public void test(Authentication authentication) { - log.info(authentication.getName()); - } -} diff --git a/src/main/java/com/_119/wepro/auth/service/AuthService.java b/src/main/java/com/_119/wepro/auth/service/AuthService.java deleted file mode 100644 index 865bde6..0000000 --- a/src/main/java/com/_119/wepro/auth/service/AuthService.java +++ /dev/null @@ -1,80 +0,0 @@ -package com._119.wepro.auth.service; - -import static com._119.wepro.global.enums.Provider.APPLE; -import static com._119.wepro.global.enums.Provider.KAKAO; - -import com._119.wepro.auth.dto.request.AuthRequest.SignInRequest; -import com._119.wepro.auth.dto.response.AuthResponse.SignInResponse; -import com._119.wepro.auth.dto.response.TokenInfo; -import com._119.wepro.auth.jwt.JwtTokenProvider; -import com._119.wepro.global.enums.Provider; -import com._119.wepro.global.enums.Role; -import com._119.wepro.member.domain.Member; -import com._119.wepro.member.domain.repository.MemberRepository; -import jakarta.transaction.Transactional; -import java.util.Map; -import java.util.Optional; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.security.oauth2.core.oidc.OidcIdToken; -import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser; -import org.springframework.security.oauth2.core.oidc.user.OidcUser; -import org.springframework.security.oauth2.jwt.Jwt; -import org.springframework.security.oauth2.jwt.JwtDecoder; -import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; -import org.springframework.stereotype.Service; - - -@Slf4j -@Service -@RequiredArgsConstructor -public class AuthService { - - private final MemberRepository memberRepository; - private final JwtTokenProvider jwtTokenProvider; - - private final Map decoders = Map.of( - Provider.KAKAO, buildDecoder(KAKAO.getJwkSetUrl()), - Provider.APPLE, buildDecoder(APPLE.getJwkSetUrl())); - - private JwtDecoder buildDecoder(String jwkUrl) { - return NimbusJwtDecoder.withJwkSetUri(jwkUrl).build(); - } - - @Transactional - public SignInResponse signIn(SignInRequest request) { - OidcUser oidcDecodePayload = socialLogin(request); - - Member member = getOrSaveUser(request, oidcDecodePayload); - TokenInfo tokenInfo = jwtTokenProvider.generateToken(member.getProviderId(), member.getRole()); - boolean isNewMember = Role.GUEST == member.getRole(); - - return new SignInResponse(isNewMember, tokenInfo); - } - - @Transactional - public void logOut(String providerId) { - jwtTokenProvider.deleteInvalidRefreshToken(providerId); - } - - - private Member getOrSaveUser(SignInRequest request, OidcUser oidcDecodePayload) { - Optional member = memberRepository.findByProviderAndProviderId( - request.getProvider(), oidcDecodePayload.getName()); - - return member.orElseGet( - () -> memberRepository.save(Member.of(request, oidcDecodePayload))); - - } - - private OidcUser socialLogin(SignInRequest request) { - Provider provider = request.getProvider(); - - Jwt jwt = decoders.get(provider).decode(request.getIdToken()); - OidcIdToken oidcIdToken = new OidcIdToken( - jwt.getTokenValue(), jwt.getIssuedAt(), jwt.getExpiresAt(), jwt.getClaims()); - - return new DefaultOidcUser(null, oidcIdToken); -// throw new RestApiException(UNSUPPORTED_PROVIDER); - } -} diff --git a/src/main/java/com/_119/wepro/auth/service/KakaoService.java b/src/main/java/com/_119/wepro/auth/service/KakaoService.java deleted file mode 100644 index 03b76bd..0000000 --- a/src/main/java/com/_119/wepro/auth/service/KakaoService.java +++ /dev/null @@ -1,73 +0,0 @@ -package com._119.wepro.auth.service; - -import com._119.wepro.auth.dto.request.AuthRequest.SignInRequest; -import com._119.wepro.auth.dto.response.AuthResponse.SignInResponse; -import com._119.wepro.global.enums.Provider; -import com._119.wepro.auth.client.KakaoOauthClient; -import com._119.wepro.auth.dto.response.KakaoTokenResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Service; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.util.UriComponentsBuilder; - -@Service -@RequiredArgsConstructor -public class KakaoService { - - private final KakaoOauthClient kakaoOauthClient; - - @Value("${login.uri}") - private String LOGIN_URI; - - @Value("${kakao.client-id}") - private String CLIENT_ID; - - @Value("${kakao.redirect-uri}") - private String REDIRECT_URI; - - @Value("${kakao.client-secret}") - private String CLIENT_SECRET; - - @Value("${kakao.authorization-uri}") - private String KAKAO_AUTH_URL; - - // 백엔드용 - public String generateKakaoRedirectUrl() { - return UriComponentsBuilder.fromUriString(KAKAO_AUTH_URL) - .queryParam("client_id", CLIENT_ID) - .queryParam("redirect_uri", REDIRECT_URI) - .queryParam("response_type", "code") - .build() - .toUriString(); - } - - // 백엔드용 - public SignInResponse handleKakaoCallback(String code) { - KakaoTokenResponse tokenResponse = kakaoOauthClient.kakaoAuth(CLIENT_ID, REDIRECT_URI, code, - CLIENT_SECRET); - String idToken = tokenResponse.getIdToken(); - ResponseEntity response = callLoginApiWithIdToken(idToken); - - return response.getBody(); - } - - // 백엔드용 - private ResponseEntity callLoginApiWithIdToken(String idToken) { - RestTemplate restTemplate = new RestTemplate(); - SignInRequest signInRequest = new SignInRequest(Provider.KAKAO, idToken); - - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); - HttpEntity requestEntity = new HttpEntity<>(signInRequest, headers); - - ResponseEntity response = restTemplate.postForEntity(LOGIN_URI, requestEntity, - SignInResponse.class); - - return response; - } -} diff --git a/src/main/java/com/_119/wepro/auth/service/RefreshService.java b/src/main/java/com/_119/wepro/auth/service/RefreshService.java deleted file mode 100644 index ed0d865..0000000 --- a/src/main/java/com/_119/wepro/auth/service/RefreshService.java +++ /dev/null @@ -1,61 +0,0 @@ -package com._119.wepro.auth.service; - -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.EXPIRED_TOKEN; -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.INVALID_TOKEN; -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.REFRESH_DENIED; - -import com._119.wepro.auth.dto.request.AuthRequest.RefreshRequest; -import com._119.wepro.auth.dto.response.TokenInfo; -import com._119.wepro.auth.jwt.JwtTokenProvider; -import com._119.wepro.global.exception.RestApiException; -import com._119.wepro.global.exception.errorcode.UserErrorCode; -import com._119.wepro.member.domain.Member; -import com._119.wepro.member.domain.repository.MemberRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class RefreshService { - - private final JwtTokenProvider jwtTokenProvider; - private final MemberRepository memberRepository; - - public TokenInfo refresh(RefreshRequest request) { - String accessToken = request.getAccessToken(); - String refreshToken = request.getRefreshToken(); - - if (!isTokenExpired(accessToken)) { - throw new RestApiException(REFRESH_DENIED); - } - String providerId = jwtTokenProvider.parseExpiredToken(accessToken) - .getSubject(); - validateRefreshToken(refreshToken, providerId); - - Member member = memberRepository.findByProviderId(providerId) - .orElseThrow(() -> new RestApiException(UserErrorCode.USER_NOT_FOUND)); - - return jwtTokenProvider.generateToken(providerId, member.getRole()); - } - - private boolean isTokenExpired(String accessToken) { - try { - jwtTokenProvider.validateToken(accessToken); - throw new RestApiException(REFRESH_DENIED); - } catch (RestApiException e) { - if (e.getErrorCode() == EXPIRED_TOKEN) { - return true; - } - throw e; - } - } - - private void validateRefreshToken(String refreshToken, String memberId) { - String savedRefreshToken = jwtTokenProvider.getRefreshToken(memberId); - if (!refreshToken.equals(savedRefreshToken)) { - throw new RestApiException(INVALID_TOKEN); - } - } -} diff --git a/src/main/java/com/_119/wepro/global/config/FeignClientConfig.java b/src/main/java/com/_119/wepro/global/config/FeignClientConfig.java deleted file mode 100644 index bf04cb7..0000000 --- a/src/main/java/com/_119/wepro/global/config/FeignClientConfig.java +++ /dev/null @@ -1,10 +0,0 @@ -package com._119.wepro.global.config; - -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableFeignClients(basePackages = "com._119.wepro.auth.client") -public class FeignClientConfig { - -} \ No newline at end of file diff --git a/src/main/java/com/_119/wepro/global/config/SecurityConfig.java b/src/main/java/com/_119/wepro/global/config/SecurityConfig.java deleted file mode 100644 index f19e5da..0000000 --- a/src/main/java/com/_119/wepro/global/config/SecurityConfig.java +++ /dev/null @@ -1,53 +0,0 @@ -package com._119.wepro.global.config; - -import com._119.wepro.auth.jwt.JwtTokenExceptionFilter; -import com._119.wepro.auth.jwt.JwtTokenFilter; -import com._119.wepro.auth.jwt.JwtTokenProvider; -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -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; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -@EnableWebSecurity -@RequiredArgsConstructor -public class SecurityConfig { - - private final JwtTokenProvider jwtTokenProvider; - - @Bean - public WebSecurityCustomizer webSecurityCustomizer() { // security를 적용하지 않을 리소스 - return web -> web.ignoring() - .requestMatchers("/css/**", "/images/**", "/js/**", "/lib/**") - .requestMatchers("/", "/swagger-ui-custom.html", "/api-docs/**", "/swagger-ui/**", - "swagger-ui.html", "/v3/api-docs/**") - .requestMatchers("/error", "/favicon.ico") - .requestMatchers("/auth/**", "/login/oauth2/code/**", "/login", "/refresh"); - } - - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http - .csrf(AbstractHttpConfigurer::disable) - .headers(header -> header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) - .sessionManagement(c -> c.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(request -> request - .requestMatchers("/", "/auth/**", "/login/oauth2/code/**", "/login").permitAll() - .requestMatchers(HttpMethod.OPTIONS).permitAll() - .anyRequest().authenticated() - ) - .logout(logout -> logout.disable()) - .addFilterBefore(new JwtTokenFilter(jwtTokenProvider), - UsernamePasswordAuthenticationFilter.class) - .addFilterBefore(new JwtTokenExceptionFilter(), JwtTokenFilter.class); - return http.build(); - } -} diff --git a/src/main/java/com/_119/wepro/global/exception/GlobalExceptionHandler.java b/src/main/java/com/_119/wepro/global/exception/GlobalExceptionHandler.java index 344e555..57d777e 100644 --- a/src/main/java/com/_119/wepro/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/_119/wepro/global/exception/GlobalExceptionHandler.java @@ -1,14 +1,13 @@ package com._119.wepro.global.exception; +import static com._119.wepro.global.exception.errorcode.CommonErrorCode.INVALID_PARAMETER; + import com._119.wepro.global.dto.ErrorResponseDto; import com._119.wepro.global.exception.errorcode.CommonErrorCode; import com._119.wepro.global.exception.errorcode.ErrorCode; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.exc.MismatchedInputException; -import feign.FeignException; import java.util.Collections; -import java.util.Map; import java.util.Objects; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,8 +22,6 @@ import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import static com._119.wepro.global.exception.errorcode.CommonErrorCode.INVALID_PARAMETER; - @RequiredArgsConstructor @RestControllerAdvice @Slf4j @@ -52,17 +49,6 @@ public ResponseEntity handleAllException(Exception ex) { return handleExceptionInternal(errorCode); } - @ExceptionHandler(FeignException.class) - public ResponseEntity feignExceptionHandler(FeignException feignException) throws JsonProcessingException { - - String responseJson = feignException.contentUTF8(); - Map responseMap = objectMapper.readValue(responseJson, Map.class); - - return ResponseEntity - .status(feignException.status()) - .body(responseMap); - } - private ResponseEntity handleExceptionInternal(ErrorCode errorCode) { return ResponseEntity.status(errorCode.getHttpStatus()).body(makeErrorResponseDto(errorCode)); } diff --git a/src/main/java/com/_119/wepro/member/service/ReissueService.java b/src/main/java/com/_119/wepro/member/service/ReissueService.java index 0596771..a09ba37 100644 --- a/src/main/java/com/_119/wepro/member/service/ReissueService.java +++ b/src/main/java/com/_119/wepro/member/service/ReissueService.java @@ -26,13 +26,13 @@ public class ReissueService { private final MemberRepository memberRepository; public void reissue(String refreshToken, String accessToken, HttpServletResponse response) { - refreshToken = extractToken(refreshToken); - accessToken = extractToken(accessToken); + String exRefreshToken = extractToken(refreshToken); + String exAccessToken = extractToken(accessToken); - validateAccessTokenExpired(accessToken); - String providerId = jwtTokenProvider.parseExpiredToken(accessToken).getSubject(); + validateAccessTokenExpired(exAccessToken); + String providerId = jwtTokenProvider.parseExpiredToken(exAccessToken).getSubject(); - validateRefreshToken(refreshToken, providerId); + validateRefreshToken(exRefreshToken, providerId); Member member = memberRepository.findByProviderId(providerId) .orElseThrow(() -> new RestApiException(UserErrorCode.USER_NOT_FOUND));