From 8486f92a5480f10c18dc1ca9cb9031cd69745fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 21 Jun 2025 12:15:34 +0900 Subject: [PATCH 1/3] =?UTF-8?q?refactor(security):=20JWT=20=ED=95=84?= =?UTF-8?q?=ED=84=B0=EA=B0=80=20=EC=9D=B8=EC=A6=9D=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=EB=A5=BC=20=EA=B1=B4=EB=84=88=EB=9B=B0?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/SecurityConfig.java | 9 +++++---- .../jwt/filter/JwtAuthenticationFilter.java | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java index f984b4f..af43297 100644 --- a/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java @@ -21,7 +21,8 @@ public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthenticationFilter; private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; - private static final String[] AUTH_WHITELIST = { + + public static final String[] AUTH_WHITELIST = { "/v3/api-docs/**", "/swagger-ui.html", "/api/v1/swagger-ui/index.html#/**", @@ -46,9 +47,9 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(customJwtAuthenticationEntryPoint)) .authorizeHttpRequests(auth -> { - auth.requestMatchers(AUTH_WHITELIST).permitAll(); - auth.anyRequest().authenticated(); - }) + auth.requestMatchers(AUTH_WHITELIST).permitAll(); + auth.anyRequest().authenticated(); + }) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) .build(); } diff --git a/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java index 48ef308..0ddaaaf 100644 --- a/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java +++ b/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java @@ -11,7 +11,9 @@ import org.springframework.http.HttpStatus; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; +import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; +import org.terning.terningserver.common.config.SecurityConfig; import org.terning.terningserver.common.security.jwt.application.JwtUserIdExtractor; import org.terning.terningserver.common.security.jwt.auth.UserAuthentication; import org.terning.terningserver.common.security.jwt.exception.JwtException; @@ -30,6 +32,18 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtUserIdExtractor jwtUserIdExtractor; private final RateLimitingService rateLimitingService; + private final AntPathMatcher antPathMatcher = new AntPathMatcher(); + + @Override + protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { + String requestURI = request.getRequestURI(); + for (String pattern : SecurityConfig.AUTH_WHITELIST) { + if (antPathMatcher.match(pattern, requestURI)) { + return true; + } + } + return false; + } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) From a720e83da3390cfca837da043debdfdf0158e384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 21 Jun 2025 12:23:55 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor(AntPathMatcher)=20:=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EB=A0=88=EB=B2=A8=20=EC=9D=B8=EC=8A=A4?= =?UTF-8?q?=ED=84=B4=EC=8A=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/security/jwt/filter/JwtAuthenticationFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java index 0ddaaaf..f5859a0 100644 --- a/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java +++ b/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java @@ -32,7 +32,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtUserIdExtractor jwtUserIdExtractor; private final RateLimitingService rateLimitingService; - private final AntPathMatcher antPathMatcher = new AntPathMatcher(); + private static final AntPathMatcher antPathMatcher = new AntPathMatcher(); @Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { From a8642afa229072ccb5f090403bd72e0d9107d150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sat, 21 Jun 2025 12:31:17 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor(security):=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=A3=BC=EC=9E=85=EC=9D=84=20=ED=86=B5=ED=95=B4=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=EC=99=80=20=EC=84=A4=EC=A0=95=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/config/SecurityConfig.java | 19 +++++++++++---- .../jwt/filter/JwtAuthenticationFilter.java | 24 ++++++++++++------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java b/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java index af43297..406602a 100644 --- a/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java +++ b/src/main/java/org/terning/terningserver/common/config/SecurityConfig.java @@ -10,8 +10,12 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.terning.terningserver.common.security.jwt.application.JwtUserIdExtractor; import org.terning.terningserver.common.security.jwt.filter.CustomJwtAuthenticationEntryPoint; import org.terning.terningserver.common.security.jwt.filter.JwtAuthenticationFilter; +import org.terning.terningserver.common.security.ratelimit.RateLimitingService; + +import java.util.List; @Configuration @EnableWebSecurity @@ -19,10 +23,11 @@ @EnableMethodSecurity public class SecurityConfig { - private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final JwtUserIdExtractor jwtUserIdExtractor; + private final RateLimitingService rateLimitingService; private final CustomJwtAuthenticationEntryPoint customJwtAuthenticationEntryPoint; - public static final String[] AUTH_WHITELIST = { + private static final List AUTH_WHITELIST = List.of( "/v3/api-docs/**", "/swagger-ui.html", "/api/v1/swagger-ui/index.html#/**", @@ -34,10 +39,16 @@ public class SecurityConfig { "/api/v1/push-status", "/api/v1/external/scraps/unsynced", "/api/v1/external/scraps/sync/result" - }; + ); @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter( + jwtUserIdExtractor, + rateLimitingService, + AUTH_WHITELIST + ); + return http .csrf(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) @@ -47,7 +58,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(customJwtAuthenticationEntryPoint)) .authorizeHttpRequests(auth -> { - auth.requestMatchers(AUTH_WHITELIST).permitAll(); + auth.requestMatchers(AUTH_WHITELIST.toArray(new String[0])).permitAll(); auth.anyRequest().authenticated(); }) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class) diff --git a/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java b/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java index f5859a0..954fa62 100644 --- a/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java +++ b/src/main/java/org/terning/terningserver/common/security/jwt/filter/JwtAuthenticationFilter.java @@ -6,14 +6,11 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; import org.springframework.util.AntPathMatcher; import org.springframework.web.filter.OncePerRequestFilter; -import org.terning.terningserver.common.config.SecurityConfig; import org.terning.terningserver.common.security.jwt.application.JwtUserIdExtractor; import org.terning.terningserver.common.security.jwt.auth.UserAuthentication; import org.terning.terningserver.common.security.jwt.exception.JwtException; @@ -21,23 +18,34 @@ import org.terning.terningserver.common.util.IpAddressUtil; import java.io.IOException; +import java.util.List; import java.util.Optional; import static org.springframework.http.HttpHeaders.AUTHORIZATION; -@Component -@RequiredArgsConstructor @Slf4j public class JwtAuthenticationFilter extends OncePerRequestFilter { + private static final AntPathMatcher antPathMatcher = new AntPathMatcher(); + private final JwtUserIdExtractor jwtUserIdExtractor; private final RateLimitingService rateLimitingService; - private static final AntPathMatcher antPathMatcher = new AntPathMatcher(); + private final List authWhitelist; + + public JwtAuthenticationFilter( + JwtUserIdExtractor jwtUserIdExtractor, + RateLimitingService rateLimitingService, + List authWhitelist + ) { + this.jwtUserIdExtractor = jwtUserIdExtractor; + this.rateLimitingService = rateLimitingService; + this.authWhitelist = authWhitelist; + } @Override - protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { + protected boolean shouldNotFilter(HttpServletRequest request) { String requestURI = request.getRequestURI(); - for (String pattern : SecurityConfig.AUTH_WHITELIST) { + for (String pattern : this.authWhitelist) { if (antPathMatcher.match(pattern, requestURI)) { return true; }