diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/GlobalHeaderOperationCustomizer.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/GlobalHeaderOperationCustomizer.java new file mode 100644 index 00000000..8b82788f --- /dev/null +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/GlobalHeaderOperationCustomizer.java @@ -0,0 +1,24 @@ +package site.timecapsulearchive.core.global.config; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.StringSchema; +import io.swagger.v3.oas.models.parameters.Parameter; +import org.springdoc.core.customizers.GlobalOperationCustomizer; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; + +@Component +public class GlobalHeaderOperationCustomizer implements GlobalOperationCustomizer { + + @Override + public Operation customize(Operation operation, HandlerMethod handlerMethod) { + Parameter customHeaderVersion = new Parameter().in(ParameterIn.HEADER.toString()) + .name("Default-Key") + .description("api key").schema(new StringSchema()) + .required(false); + + operation.addParametersItem(customHeaderVersion); + return operation; + } +} \ No newline at end of file diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java index f71652fc..470c084a 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/config/security/SecurityConfig.java @@ -20,6 +20,7 @@ import org.springframework.security.web.util.matcher.RequestMatchers; import site.timecapsulearchive.core.domain.member.entity.Role; import site.timecapsulearchive.core.global.security.filter.DefaultAuthenticationFilter; +import site.timecapsulearchive.core.global.security.property.DefaultKeyProperties; @EnableWebSecurity @Configuration @@ -28,8 +29,8 @@ public class SecurityConfig { private final AuthenticationProvider jwtAuthenticationProvider; private final ObjectMapper objectMapper; + private final DefaultKeyProperties defaultKeyProperties; private final AccessDeniedHandler accessDeniedHandler; - private final DefaultAuthenticationFilter defaultAuthenticationFilter; @Bean public PasswordEncoder getPasswordEncoder() { @@ -57,7 +58,8 @@ public SecurityFilterChain filterChainWithJwt(final HttpSecurity http) throws Ex .exceptionHandling(error -> error.accessDeniedHandler(accessDeniedHandler)); http.addFilterBefore( - defaultAuthenticationFilter, + new DefaultAuthenticationFilter(defaultKeyProperties, + notRequireDefaultAuthenticationMatcher()), UsernamePasswordAuthenticationFilter.class ); @@ -89,6 +91,15 @@ private RequestMatcher notRequireAuthenticationMatcher() { antMatcher(HttpMethod.GET, "/actuator/**") ); } + + private RequestMatcher notRequireDefaultAuthenticationMatcher() { + return RequestMatchers.anyOf( + antMatcher("/v3/api-docs/**"), + antMatcher("/swagger-ui/**"), + antMatcher(HttpMethod.GET, "/health"), + antMatcher(HttpMethod.GET, "/actuator/**") + ); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/log/LoggingComponent.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/log/LoggingComponent.java index b9674451..7e2d86bc 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/log/LoggingComponent.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/log/LoggingComponent.java @@ -28,7 +28,10 @@ public Object logRepositoryLayer(ProceedingJoinPoint joinPoint) throws Throwable return logMethod(joinPoint, "Repository"); } - @Around("execution(public * site.timecapsulearchive.core.infra.*.manager.*.*(..))") + @Around(""" + execution(public * site.timecapsulearchive.core.infra.*.manager.*.*(..)) + && !execution(public * site.timecapsulearchive.core.infra.s3.manager.*.*(..)) + """) public Object logExternalApi(ProceedingJoinPoint joinPoint) throws Throwable { return logMethod(joinPoint, "External API"); } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/filter/DefaultAuthenticationFilter.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/filter/DefaultAuthenticationFilter.java index 8db5276f..a313b105 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/filter/DefaultAuthenticationFilter.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/filter/DefaultAuthenticationFilter.java @@ -8,28 +8,31 @@ import java.io.IOException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.core.annotation.Order; import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; +import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.web.filter.OncePerRequestFilter; import site.timecapsulearchive.core.global.error.ErrorCode; import site.timecapsulearchive.core.global.error.ErrorResponse; import site.timecapsulearchive.core.global.security.property.DefaultKeyProperties; @Slf4j -@Component @RequiredArgsConstructor public class DefaultAuthenticationFilter extends OncePerRequestFilter { private final DefaultKeyProperties defaultKeyProperties; + private final RequestMatcher notRequireDefaultAuthenticationMatcher; @Override - @Order(1) protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException { + if (notRequiresAuthentication(request)) { + filterChain.doFilter(request, response); + return; + } + String requestKey = request.getHeader("Default-Key"); if (requestKey == null || !requestKey.equals(defaultKeyProperties.defaultKey())) { @@ -53,4 +56,8 @@ protected void doFilterInternal( filterChain.doFilter(request, response); } + + private boolean notRequiresAuthentication(final HttpServletRequest request) { + return notRequireDefaultAuthenticationMatcher.matches(request); + } } diff --git a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java index f5410ab6..c82c3d70 100644 --- a/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java +++ b/backend/core/src/main/java/site/timecapsulearchive/core/global/security/jwt/JwtAuthenticationFilter.java @@ -33,7 +33,6 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final RequestMatcher notRequireAuthenticationMatcher; @Override - @Order(2) protected void doFilterInternal( final HttpServletRequest request, final HttpServletResponse response, diff --git a/backend/core/src/test/java/site/timecapsulearchive/core/common/config/TestMockMvcSecurityConfig.java b/backend/core/src/test/java/site/timecapsulearchive/core/common/config/TestMockMvcSecurityConfig.java index b74fa25b..f4375b2d 100644 --- a/backend/core/src/test/java/site/timecapsulearchive/core/common/config/TestMockMvcSecurityConfig.java +++ b/backend/core/src/test/java/site/timecapsulearchive/core/common/config/TestMockMvcSecurityConfig.java @@ -90,7 +90,7 @@ public DefaultKeyProperties testDefaultKeyProperties() { @Order(1) public DefaultAuthenticationFilter testDefaultAuthenticationFilter( ) { - return new DefaultAuthenticationFilter(testDefaultKeyProperties()); + return new DefaultAuthenticationFilter(testDefaultKeyProperties(), notRequireAuthenticationMatcher()); } @Bean