diff --git a/src/main/java/com/gaebaljip/exceed/common/EatCeedStaticMessage.java b/src/main/java/com/gaebaljip/exceed/common/EatCeedStaticMessage.java index 4aebeec7..2f3341cf 100644 --- a/src/main/java/com/gaebaljip/exceed/common/EatCeedStaticMessage.java +++ b/src/main/java/com/gaebaljip/exceed/common/EatCeedStaticMessage.java @@ -5,4 +5,14 @@ public class EatCeedStaticMessage { public static final String REDIS_REFRESH_TOKEN_KEY = "refresh_"; public static final String REFRESH_TOKEN = "refreshToken"; + public static final String[] SwaggerPatterns = { + "/swagger-resources/**", + "/swagger-ui/**", + "/swagger-ui.html", + "/v3/api-docs/**", + "/v3/api-docs", + "/api-docs/**", + "/api-docs", + "/docs/api-doc.html" + }; } diff --git a/src/main/java/com/gaebaljip/exceed/common/security/config/SecurityConfig.java b/src/main/java/com/gaebaljip/exceed/common/security/config/SecurityConfig.java index 67df47ab..051460fa 100644 --- a/src/main/java/com/gaebaljip/exceed/common/security/config/SecurityConfig.java +++ b/src/main/java/com/gaebaljip/exceed/common/security/config/SecurityConfig.java @@ -11,6 +11,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsUtils; +import com.gaebaljip.exceed.common.helper.SpringEnvironmentHelper; import com.gaebaljip.exceed.common.security.domain.JwtManager; import com.gaebaljip.exceed.common.security.domain.JwtResolver; import com.gaebaljip.exceed.common.security.exception.JwtAccessDeniedHandler; @@ -29,6 +30,7 @@ public class SecurityConfig { private final MemberDetailService memberDetailService; private final JwtAuthenticationPoint jwtAuthenticationPoint; private final JwtAccessDeniedHandler jwtAccessDeniedHandler; + private final SpringEnvironmentHelper springEnvironmentHelper; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -77,12 +79,22 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .permitAll() .antMatchers(HttpMethod.POST, "/v1/auth/login", "/v1/auth/refresh") .permitAll() + .antMatchers( + "/swagger-resources/**", + "/swagger-ui/**", + "/swagger-ui.html", + "/v3/api-docs/**", + "/v3/api-docs", + "/api-docs/**", + "/api-docs") + .permitAll() .anyRequest() .authenticated(); // jwt filter 설정 http.addFilterBefore( - new JwtAuthenticationFilter(jwtManager, jwtResolver, memberDetailService), + new JwtAuthenticationFilter( + jwtManager, jwtResolver, memberDetailService, springEnvironmentHelper), UsernamePasswordAuthenticationFilter.class); return http.build(); } @@ -91,16 +103,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring() - .antMatchers("/docs/api-doc.html") .antMatchers("/favicon.*", "/*/icon-*") - .antMatchers( - "/swagger-resources/**", - "/swagger-ui/**", - "/swagger-ui.html", - "/v3/api-docs/**", - "/v3/api-docs", - "/api-docs/**", - "/api-docs") .requestMatchers(PathRequest.toStaticResources().atCommonLocations()); } } diff --git a/src/main/java/com/gaebaljip/exceed/common/security/exception/JwtAuthenticationPoint.java b/src/main/java/com/gaebaljip/exceed/common/security/exception/JwtAuthenticationPoint.java index d3269330..14c8afeb 100644 --- a/src/main/java/com/gaebaljip/exceed/common/security/exception/JwtAuthenticationPoint.java +++ b/src/main/java/com/gaebaljip/exceed/common/security/exception/JwtAuthenticationPoint.java @@ -36,11 +36,13 @@ public void commence( HttpServletResponse response, AuthenticationException authException) throws IOException { - if (request.getAttribute("exception") == null) { + Object exceptionAttribute = request.getAttribute("javax.servlet.error.exception"); + if (exceptionAttribute == null) { handleAuthenticationException(response); + } else if (exceptionAttribute instanceof Exception exception) { + resolver.resolveException(request, response, null, exception); } else { - resolver.resolveException( - request, response, null, (Exception) request.getAttribute("exception")); + handleAuthenticationException(response); } } diff --git a/src/main/java/com/gaebaljip/exceed/common/security/filter/JwtAuthenticationFilter.java b/src/main/java/com/gaebaljip/exceed/common/security/filter/JwtAuthenticationFilter.java index 9eadd015..2ffa972e 100644 --- a/src/main/java/com/gaebaljip/exceed/common/security/filter/JwtAuthenticationFilter.java +++ b/src/main/java/com/gaebaljip/exceed/common/security/filter/JwtAuthenticationFilter.java @@ -1,5 +1,7 @@ package com.gaebaljip.exceed.common.security.filter; +import static com.gaebaljip.exceed.common.EatCeedStaticMessage.SwaggerPatterns; + import java.io.IOException; import java.time.LocalDateTime; import java.util.List; @@ -13,12 +15,15 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.util.PatternMatchUtils; import org.springframework.web.filter.OncePerRequestFilter; +import com.gaebaljip.exceed.common.helper.SpringEnvironmentHelper; import com.gaebaljip.exceed.common.security.domain.JwtManager; import com.gaebaljip.exceed.common.security.domain.JwtResolver; import com.gaebaljip.exceed.common.security.domain.MemberDetails; import com.gaebaljip.exceed.common.security.service.MemberDetailService; +import com.gaebaljip.exceed.common.swagger.SwaggerCannotProdException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -30,6 +35,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtManager jwtManager; private final JwtResolver jwtResolver; private final MemberDetailService memberDetailService; + private final SpringEnvironmentHelper springEnvironmentHelper; private final List excludeUrl = List.of("/actuator", "/v1/health"); @Override @@ -37,6 +43,12 @@ protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // prod 환경에서 swagger 요청을 차단 + if (Boolean.TRUE.equals(springEnvironmentHelper.isProdProfile()) + && isSwaggerRequest(request)) { + throw SwaggerCannotProdException.EXCEPTION; + } + final String bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION); if (bearerToken == null || !bearerToken.startsWith("Bearer ")) { filterChain.doFilter(request, response); @@ -84,4 +96,9 @@ protected boolean shouldNotFilter(HttpServletRequest request) throws ServletExce } return flag; } + + private boolean isSwaggerRequest(HttpServletRequest request) { + String servletPath = request.getServletPath(); + return PatternMatchUtils.simpleMatch(SwaggerPatterns, servletPath); + } }