From 210ffb9cd64fc9d2a56364f9420c16f54b981e7c Mon Sep 17 00:00:00 2001 From: yoonho Date: Wed, 10 Dec 2025 16:11:38 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[#9]=20chore:=20yaml=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/helm-value.yaml | 6 ++++ src/main/resources/application-dev.yaml | 38 --------------------- src/main/resources/application-local.yaml | 41 +---------------------- src/main/resources/application-test.yaml | 41 +---------------------- src/main/resources/application.yaml | 33 +++++++++++++++++- 5 files changed, 40 insertions(+), 119 deletions(-) diff --git a/k8s/helm-value.yaml b/k8s/helm-value.yaml index cec13e8..e11c757 100644 --- a/k8s/helm-value.yaml +++ b/k8s/helm-value.yaml @@ -1,2 +1,8 @@ image: tag: v0.1.1 +env: + MEMBER_URI: "http://backend-member:8080" + SIGHT_URI: "http://backend-sight:8080" + STORY_URI: "http://backend-story:8080" + CORE_URI: "http://backend-core:8080" + ROUTE_URI: "http://backend-route:8080" \ No newline at end of file diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 5ece495..4bd0ee8 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -2,44 +2,6 @@ spring: config: import: - optional:file:/etc/secret/application-secret.yaml - - application: - name: backend-gateway - - cloud: - gateway: - server: - webmvc: - routes: - - id: backend-member - uri: http://backend-member:8080 - predicates: - - Path=/api/member/**, /api/user/member/**, /api/admin/member/** - - - id: backend-sight - uri: http://backend-sight:8080 - predicates: - - Path=/api/sight/**, /api/user/sight/**, /api/admin/sight/** - - - id: backend-story - uri: http://backend-story:8080 - predicates: - - Path=/api/story/**, /api/user/story/**, /api/admin/story/** - - - id: backend-core - uri: http://backend-core:8080 - predicates: - - Path=/api/core/**, /api/user/core/**, /api/admin/core/** - - - id: backend-route - uri: http://backend-route:8080 - predicates: - - Path=/api/route/**, /api/user/route/**, /api/admin/route/** - - - id: backend-search - uri: http://backend-search:8080 - predicates: - - Path=/api/search/**, /api/user/search/**, /api/admin/search/** otel: propagators: - tracecontext diff --git a/src/main/resources/application-local.yaml b/src/main/resources/application-local.yaml index 503bac4..b73c439 100644 --- a/src/main/resources/application-local.yaml +++ b/src/main/resources/application-local.yaml @@ -1,47 +1,8 @@ server: port: 8080 -spring: - application: - name: backend-gateway - - cloud: - gateway: - server: - webmvc: - routes: - - id: backend-member - uri: http://backend-member:8080 - predicates: - - Path=/api/member/**, /api/user/member/**, /api/admin/member/** - - - id: backend-sight - uri: http://backend-sight:8080 - predicates: - - Path=/api/sight/**, /api/user/sight/**, /api/admin/sight/** - - - id: backend-story - uri: http://backend-story:8080 - predicates: - - Path=/api/story/**, /api/user/story/**, /api/admin/story/** - - - id: backend-core - uri: http://backend-core:8080 - predicates: - - Path=/api/core/**, /api/user/core/**, /api/admin/core/** - - - id: backend-route - uri: http://backend-route:8080 - predicates: - - Path=/api/route/**, /api/user/route/**, /api/admin/route/** - - - id: backend-search - uri: http://backend-search:8080 - predicates: - - Path=/api/search/**, /api/user/search/**, /api/admin/search/** - jwt: - access_secret: AADfaskllew3skllew32dsfasdTG764G2dsfasdTG764GDfaskllew3skllew32dsfasdTG764G2ddskllew32dsfasdTG764G + access_secret: ${JWT_SECRET} management: endpoints: diff --git a/src/main/resources/application-test.yaml b/src/main/resources/application-test.yaml index 156566c..dff0097 100644 --- a/src/main/resources/application-test.yaml +++ b/src/main/resources/application-test.yaml @@ -1,47 +1,8 @@ server: port: 8080 -spring: - application: - name: backend-gateway - - cloud: - gateway: - server: - webmvc: - routes: - - id: backend-member - uri: http://backend-member:8080 - predicates: - - Path=/api/member/**, /api/user/member/**, /api/admin/member/** - - - id: backend-sight - uri: http://backend-sight:8080 - predicates: - - Path=/api/sight/**, /api/user/sight/**, /api/admin/sight/** - - - id: backend-story - uri: http://backend-story:8080 - predicates: - - Path=/api/story/**, /api/user/story/**, /api/admin/story/** - - - id: backend-core - uri: http://backend-core:8080 - predicates: - - Path=/api/core/**, /api/user/core/**, /api/admin/core/** - - - id: backend-route - uri: http://backend-route:8080 - predicates: - - Path=/api/route/**, /api/user/route/**, /api/admin/route/** - - - id: backend-search - uri: http://backend-search:8080 - predicates: - - Path=/api/search/**, /api/user/search/**, /api/admin/search/** - jwt: - access_secret: AADfaskllew3skllew32dsfasdTG764G2dsfasdTG764GDfaskllew3skllew32dsfasdTG764G2ddskllew32dsfasdTG764G + access_secret: ${JWT_SECRET} management: metrics: diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 66f574e..91ed31b 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,3 +1,34 @@ spring: profiles: - default: local \ No newline at end of file + default: local + application: + name: backend-gateway + cloud: + gateway: + server: + webmvc: + routes: + - id: backend-member + uri: ${MEMBER_URI} + predicates: + - Path=/api/member/**, /api/user/member/**, /api/admin/member/** + + - id: backend-sight + uri: ${SIGHT_URI} + predicates: + - Path=/api/sight/**, /api/user/sight/**, /api/admin/sight/** + + - id: backend-story + uri: ${STORY_URI} + predicates: + - Path=/api/story/**, /api/user/story/**, /api/admin/story/** + + - id: backend-core + uri: ${CORE_URI} + predicates: + - Path=/api/core/**, /api/user/core/**, /api/admin/core/** + + - id: backend-route + uri: ${ROUTE_URI} + predicates: + - Path=/api/route/**, /api/user/route/**, /api/admin/route/** \ No newline at end of file From 2326c00532f231c21c330819dda553920a531351 Mon Sep 17 00:00:00 2001 From: yoonho Date: Thu, 11 Dec 2025 21:20:46 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[#9]=20feat:=20swagger=20=ED=86=B5=ED=95=A9?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/helm-value.yaml | 8 ++- .../common/config/WebSecurityConfig.java | 10 ++- .../security/jwt/JwtAuthenticationFilter.java | 18 ++++-- src/main/resources/application.yaml | 62 +++++++++++++++++-- 4 files changed, 86 insertions(+), 12 deletions(-) diff --git a/k8s/helm-value.yaml b/k8s/helm-value.yaml index e11c757..93c58da 100644 --- a/k8s/helm-value.yaml +++ b/k8s/helm-value.yaml @@ -5,4 +5,10 @@ env: SIGHT_URI: "http://backend-sight:8080" STORY_URI: "http://backend-story:8080" CORE_URI: "http://backend-core:8080" - ROUTE_URI: "http://backend-route:8080" \ No newline at end of file + ROUTE_URI: "http://backend-route:8080" + MEMBER_API_PATH: "/api/member/**, /api/user/member/**, /api/admin/member/**" + SIGHT_API_PATH: "/api/sight/**, /api/user/sight/**, /api/admin/sight/**" + STORY_API_PATH: "/api/story/**, /api/user/story/**, /api/admin/story/**" + CORE_API_PATH: "/api/core/**, /api/user/core/**, /api/admin/core/**" + ROUTE_API_PATH: "/api/route/**, /api/user/route/**, /api/admin/route/**" + PUBLIC_PATHS: "/.well-known/**,/favicon.ico,/error,/swagger-ui/**,/swagger-ui.html,/api-docs/**,/member/api-docs,/sight/api-docs,/story/api-docs,/core/api-docs,/route/api-docs,/actuator/**,/api/**" \ No newline at end of file diff --git a/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java b/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java index f2a8639..69c2acd 100644 --- a/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java +++ b/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java @@ -4,6 +4,7 @@ import com.earseo.gateway.security.jwt.CustomAuthenticationEntryPoint; import com.earseo.gateway.security.jwt.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -23,6 +24,8 @@ @RequiredArgsConstructor public class WebSecurityConfig { + @Value("${security.path.public}") + private String publicPaths; private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint; private final CustomAccessDeniedHandler customAccessDeniedHandler; @@ -40,8 +43,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .authorizeHttpRequests(authorizeRequests -> authorizeRequests .requestMatchers("/api/user/**").hasAnyAuthority("USER", "ADMIN") .requestMatchers("/api/admin/**").hasAuthority("ADMIN") - .requestMatchers("/api/**").permitAll() - .requestMatchers("/actuator/**").permitAll() + .requestMatchers(this.getPublicPaths()).permitAll() .anyRequest().authenticated()) .exceptionHandling(exceptionHandler -> exceptionHandler .authenticationEntryPoint(customAuthenticationEntryPoint) @@ -65,4 +67,8 @@ public CorsConfigurationSource corsConfigurationSource() { return source; } + + private String[] getPublicPaths() { + return publicPaths.split(","); + } } diff --git a/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java index 1c79b0c..2c630fa 100644 --- a/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java @@ -8,6 +8,7 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -24,6 +25,8 @@ @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { + @Value("${security.path.public}") + private String publicPaths; private final JwtValidator jwtValidator; private final HandlerExceptionResolver resolver; private static final AntPathMatcher pathMatcher = new AntPathMatcher(); @@ -69,12 +72,19 @@ protected void doFilterInternal(HttpServletRequest request, } @Override - protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { + protected boolean shouldNotFilter(HttpServletRequest request) { String path = request.getRequestURI(); + String[] paths = publicPaths.split(","); - return !pathMatcher.match("/api/user/**", path) && - !pathMatcher.match("/api/admin/**", path) && - pathMatcher.match("/api/**", path); + boolean skip = false; + for (String pattern : paths) { + if (pathMatcher.match(pattern, path)) { + skip = true; + break; + } + } + log.info("Path: {} - Skip Filter: {}", path, skip); + return skip; } private static class MutableHttpServletRequest extends HttpServletRequestWrapper { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 91ed31b..45fc0b3 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -11,24 +11,76 @@ spring: - id: backend-member uri: ${MEMBER_URI} predicates: - - Path=/api/member/**, /api/user/member/**, /api/admin/member/** + - Path=${MEMBER_API_PATH} - id: backend-sight uri: ${SIGHT_URI} predicates: - - Path=/api/sight/**, /api/user/sight/**, /api/admin/sight/** + - Path=${SIGHT_API_PATH} - id: backend-story uri: ${STORY_URI} predicates: - - Path=/api/story/**, /api/user/story/**, /api/admin/story/** + - Path=${STORY_API_PATH} - id: backend-core uri: ${CORE_URI} predicates: - - Path=/api/core/**, /api/user/core/**, /api/admin/core/** + - Path=${CORE_API_PATH} - id: backend-route uri: ${ROUTE_URI} predicates: - - Path=/api/route/**, /api/user/route/**, /api/admin/route/** \ No newline at end of file + - Path=${ROUTE_API_PATH} + + - id: member-openapi + uri: ${MEMBER_URI} + predicates: + - Path=/member/api-docs + filters: + - RewritePath=/member/api-docs, /api-docs + + - id: sight-openapi + uri: ${SIGHT_URI} + predicates: + - Path=/sight/api-docs + filters: + - RewritePath=/sight/api-docs, /api-docs + + - id: story-openapi + uri: ${STORY_URI} + predicates: + - Path=/story/api-docs + filters: + - RewritePath=/story/api-docs, /api-docs + + - id: core-openapi + uri: ${CORE_URI} + predicates: + - Path=/core/api-docs + filters: + - RewritePath=/core/api-docs, /api-docs +springdoc: + api-docs: + enabled: true + path: /api-docs + swagger-ui: + enabled: true + path: /swagger-ui.html + display-request-duration: true + operations-sorter: method + tags-sorter: alpha + urls: + - name: backend-member + url: /member/api-docs + - name: backend-sight + url: /sight/api-docs + - name: backend-story + url: /story/api-docs + - name: backend-core + url: /core/api-docs + - name: backend-route + url: /route/api-docs +security: + path: + public: ${PUBLIC_PATHS} From 1ce8bbbc05b431c6f1419e13279a8ae39ea41dd3 Mon Sep 17 00:00:00 2001 From: yoonho Date: Thu, 11 Dec 2025 21:46:56 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[#9]=20fix:=20test=20=ED=99=98=EA=B2=BD?= =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-test.yaml | 2 +- src/main/resources/application.yaml | 31 ++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/resources/application-test.yaml b/src/main/resources/application-test.yaml index dff0097..e0071a9 100644 --- a/src/main/resources/application-test.yaml +++ b/src/main/resources/application-test.yaml @@ -2,7 +2,7 @@ server: port: 8080 jwt: - access_secret: ${JWT_SECRET} + access_secret: ${JWT_SECRET:jwtsecretkeyjwtsecretkeyjwtsecretkeyjwtsecretkeyjwtsecretkeyjwtsecretkey} management: metrics: diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 45fc0b3..e100279 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -9,53 +9,53 @@ spring: webmvc: routes: - id: backend-member - uri: ${MEMBER_URI} + uri: ${MEMBER_URI:http://example.com} predicates: - - Path=${MEMBER_API_PATH} + - Path=${MEMBER_API_PATH:/member} - id: backend-sight - uri: ${SIGHT_URI} + uri: ${SIGHT_URI:http://example.com} predicates: - - Path=${SIGHT_API_PATH} + - Path=${SIGHT_API_PATH:/sight} - id: backend-story - uri: ${STORY_URI} + uri: ${STORY_URI:http://example.com} predicates: - - Path=${STORY_API_PATH} + - Path=${STORY_API_PATH:/story} - id: backend-core - uri: ${CORE_URI} + uri: ${CORE_URI:http://example.com} predicates: - - Path=${CORE_API_PATH} + - Path=${CORE_API_PATH:/core} - id: backend-route - uri: ${ROUTE_URI} + uri: ${ROUTE_URI:http://example.com} predicates: - - Path=${ROUTE_API_PATH} + - Path=${ROUTE_API_PATH:/route} - id: member-openapi - uri: ${MEMBER_URI} + uri: ${MEMBER_URI:http://example.com} predicates: - Path=/member/api-docs filters: - RewritePath=/member/api-docs, /api-docs - id: sight-openapi - uri: ${SIGHT_URI} + uri: ${SIGHT_URI:http://example.com} predicates: - Path=/sight/api-docs filters: - RewritePath=/sight/api-docs, /api-docs - id: story-openapi - uri: ${STORY_URI} + uri: ${STORY_URI:http://example.com} predicates: - Path=/story/api-docs filters: - RewritePath=/story/api-docs, /api-docs - id: core-openapi - uri: ${CORE_URI} + uri: ${CORE_URI:http://example.com} predicates: - Path=/core/api-docs filters: @@ -65,6 +65,7 @@ springdoc: enabled: true path: /api-docs swagger-ui: + use-root-path: true enabled: true path: /swagger-ui.html display-request-duration: true @@ -83,4 +84,4 @@ springdoc: url: /route/api-docs security: path: - public: ${PUBLIC_PATHS} + public: ${PUBLIC_PATHS:publicpaths} From a089f169190dfa4e40149395622626230097130a Mon Sep 17 00:00:00 2001 From: yoonho Date: Fri, 12 Dec 2025 04:48:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[#9]=20feat:=20swagger=20=EC=9D=B8=EA=B0=80?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20-=20=ED=97=88=EA=B0=80=EB=90=9C=20?= =?UTF-8?q?=ED=98=B8=EC=8A=A4=ED=8A=B8=EB=A7=8C=20swagger=EC=97=90=20?= =?UTF-8?q?=EC=A0=91=EA=B7=BC=EA=B0=80=EB=8A=A5=ED=95=98=EA=B2=8C=20filter?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/helm-value.yaml | 3 +- .../common/config/WebSecurityConfig.java | 3 + .../gateway/common/exception/AuthError.java | 2 + .../gateway/security/SwaggerFilter.java | 66 +++++++++++++++++++ .../security/jwt/JwtAuthenticationFilter.java | 25 ++++--- src/main/resources/application.yaml | 4 ++ 6 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/earseo/gateway/security/SwaggerFilter.java diff --git a/k8s/helm-value.yaml b/k8s/helm-value.yaml index 93c58da..ebba5be 100644 --- a/k8s/helm-value.yaml +++ b/k8s/helm-value.yaml @@ -11,4 +11,5 @@ env: STORY_API_PATH: "/api/story/**, /api/user/story/**, /api/admin/story/**" CORE_API_PATH: "/api/core/**, /api/user/core/**, /api/admin/core/**" ROUTE_API_PATH: "/api/route/**, /api/user/route/**, /api/admin/route/**" - PUBLIC_PATHS: "/.well-known/**,/favicon.ico,/error,/swagger-ui/**,/swagger-ui.html,/api-docs/**,/member/api-docs,/sight/api-docs,/story/api-docs,/core/api-docs,/route/api-docs,/actuator/**,/api/**" \ No newline at end of file + PUBLIC_PATHS: "/.well-known/**,/favicon.ico,/error,/swagger-ui/**,/swagger-ui.html,/api-docs/**,/member/api-docs,/sight/api-docs,/story/api-docs,/core/api-docs,/route/api-docs,/actuator/**,/api/**" + AUTH_PATHS: "/api/user/**,/api/admin/**" \ No newline at end of file diff --git a/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java b/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java index 69c2acd..95a87be 100644 --- a/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java +++ b/src/main/java/com/earseo/gateway/common/config/WebSecurityConfig.java @@ -1,5 +1,6 @@ package com.earseo.gateway.common.config; +import com.earseo.gateway.security.SwaggerFilter; import com.earseo.gateway.security.jwt.CustomAccessDeniedHandler; import com.earseo.gateway.security.jwt.CustomAuthenticationEntryPoint; import com.earseo.gateway.security.jwt.JwtAuthenticationFilter; @@ -29,6 +30,7 @@ public class WebSecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint; private final CustomAccessDeniedHandler customAccessDeniedHandler; + private final SwaggerFilter swaggerFilter; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -39,6 +41,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti sessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .formLogin(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) + .addFilterBefore(swaggerFilter, UsernamePasswordAuthenticationFilter.class) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(authorizeRequests -> authorizeRequests .requestMatchers("/api/user/**").hasAnyAuthority("USER", "ADMIN") diff --git a/src/main/java/com/earseo/gateway/common/exception/AuthError.java b/src/main/java/com/earseo/gateway/common/exception/AuthError.java index f8d6147..6e6cea3 100644 --- a/src/main/java/com/earseo/gateway/common/exception/AuthError.java +++ b/src/main/java/com/earseo/gateway/common/exception/AuthError.java @@ -10,6 +10,8 @@ public enum AuthError implements ErrorCodeInterface{ EXPIRED_TOKEN("AUTH_001", "토큰이 만료되었습니다.", HttpStatus.BAD_REQUEST), INVALID_TOKEN("AUTH_002", "유효하지 않은 토큰입니다.", HttpStatus.BAD_REQUEST), UNSUPPORTED_JWT("AUTH_003", "지원하지 않는 토큰입니다.", HttpStatus.BAD_REQUEST), + + DISALLOWED_HOST("GATE_001","허가되지 않은 호스트입니다.",HttpStatus.FORBIDDEN), ; private final String status; diff --git a/src/main/java/com/earseo/gateway/security/SwaggerFilter.java b/src/main/java/com/earseo/gateway/security/SwaggerFilter.java new file mode 100644 index 0000000..73f5fba --- /dev/null +++ b/src/main/java/com/earseo/gateway/security/SwaggerFilter.java @@ -0,0 +1,66 @@ +package com.earseo.gateway.security; + +import com.earseo.gateway.common.exception.AuthError; +import com.earseo.gateway.common.exception.BaseException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.servlet.HandlerExceptionResolver; + +import java.util.List; + +@Component +public class SwaggerFilter extends OncePerRequestFilter { + + @Value("${allowed.hosts}") + private List allowedHosts; + private final HandlerExceptionResolver resolver; + + private static final AntPathMatcher pathMatcher = new AntPathMatcher(); + + public SwaggerFilter( @Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) { + this.resolver = resolver; + } + + @Override + protected void doFilterInternal(HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) { + + try { + String host = request.getHeader("Host"); + + if (host == null || !isAllowedHost(host)) { + throw new BaseException(AuthError.DISALLOWED_HOST); + } + + filterChain.doFilter(request, response); + + } catch (Exception e) { + resolver.resolveException(request, response, null, e); + } + } + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) { + String path = request.getRequestURI(); + + return !pathMatcher.match("/swagger-ui/**", path) && + !pathMatcher.match("/swagger-ui.html", path) && + !pathMatcher.match("/**/api-docs", path) && + !pathMatcher.match("/api-docs/**", path); + } + + private boolean isAllowedHost(String host) { + //port 제거 + String hostname = host.split(":")[0]; + + return allowedHosts.stream() + .anyMatch(hostname::equals); + } +} diff --git a/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java b/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java index 2c630fa..d78e0ab 100644 --- a/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/earseo/gateway/security/jwt/JwtAuthenticationFilter.java @@ -6,7 +6,6 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -21,12 +20,13 @@ import java.io.IOException; import java.util.*; -@Slf4j @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { @Value("${security.path.public}") - private String publicPaths; + private String publicPath; + @Value("${security.path.auth}") + private String authPath; private final JwtValidator jwtValidator; private final HandlerExceptionResolver resolver; private static final AntPathMatcher pathMatcher = new AntPathMatcher(); @@ -74,17 +74,22 @@ protected void doFilterInternal(HttpServletRequest request, @Override protected boolean shouldNotFilter(HttpServletRequest request) { String path = request.getRequestURI(); - String[] paths = publicPaths.split(","); + String[] publicPaths = publicPath.split(","); + String[] authPaths = authPath.split(","); - boolean skip = false; - for (String pattern : paths) { + for (String pattern : authPaths) { if (pathMatcher.match(pattern, path)) { - skip = true; - break; + return false; } } - log.info("Path: {} - Skip Filter: {}", path, skip); - return skip; + + for (String pattern : publicPaths) { + if (pathMatcher.match(pattern, path)) { + return true; + } + } + + return false; } private static class MutableHttpServletRequest extends HttpServletRequestWrapper { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index e100279..353b8bd 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -85,3 +85,7 @@ springdoc: security: path: public: ${PUBLIC_PATHS:publicpaths} + auth: ${AUTH_PATHS:authpaths} + +allowed: + hosts: ${ALLOWED_HOST:localhost}