From 1f01ddb75053416b6de2e32d61dc246e044e1c16 Mon Sep 17 00:00:00 2001 From: kevstevie Date: Sat, 28 Oct 2023 20:11:31 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20interceptor=20http=20method?= =?UTF-8?q?=EB=8F=84=20=EC=A7=80=EC=A0=95=ED=95=98=EA=B2=8C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yigongil/backend/config/AuthConfig.java | 38 +++++++++++------- .../backend/config/auth/AuthInterceptor.java | 16 -------- .../backend/config/auth/path/HttpMethod.java | 20 ++++++++++ .../config/auth/path/PathContainer.java | 36 +++++++++++++++++ .../config/auth/path/PathInterceptor.java | 39 +++++++++++++++++++ .../backend/config/auth/path/PathPattern.java | 24 ++++++++++++ 6 files changed, 144 insertions(+), 29 deletions(-) create mode 100644 backend/src/main/java/com/yigongil/backend/config/auth/path/HttpMethod.java create mode 100644 backend/src/main/java/com/yigongil/backend/config/auth/path/PathContainer.java create mode 100644 backend/src/main/java/com/yigongil/backend/config/auth/path/PathInterceptor.java create mode 100644 backend/src/main/java/com/yigongil/backend/config/auth/path/PathPattern.java diff --git a/backend/src/main/java/com/yigongil/backend/config/AuthConfig.java b/backend/src/main/java/com/yigongil/backend/config/AuthConfig.java index c75fefac1..ed022fe38 100644 --- a/backend/src/main/java/com/yigongil/backend/config/AuthConfig.java +++ b/backend/src/main/java/com/yigongil/backend/config/AuthConfig.java @@ -1,10 +1,17 @@ package com.yigongil.backend.config; +import static com.yigongil.backend.config.auth.path.HttpMethod.ANY; +import static com.yigongil.backend.config.auth.path.HttpMethod.GET; +import static com.yigongil.backend.config.auth.path.HttpMethod.POST; +import static com.yigongil.backend.config.auth.path.HttpMethod.PUT; + import com.yigongil.backend.config.auth.AuthInterceptor; import com.yigongil.backend.config.auth.MemberArgumentResolver; +import com.yigongil.backend.config.auth.path.PathInterceptor; import java.util.List; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -21,20 +28,25 @@ public AuthConfig(MemberArgumentResolver memberArgumentResolver, AuthInterceptor @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(authInterceptor) - .addPathPatterns("/**") - .excludePathPatterns("/login/github/tokens") - .excludePathPatterns("/login/tokens/refresh") - .excludePathPatterns("/login/fake/tokens") - .excludePathPatterns("/members/{id:[0-9]\\d*}") - .excludePathPatterns("/members/exists") - .excludePathPatterns("/api/**") - .excludePathPatterns("/api-docs/**") - .excludePathPatterns("/swagger-ui/**") - .excludePathPatterns("/actuator/**") - .excludePathPatterns("/fake/proceed") - .excludePathPatterns("/studies/{id:[0-9]\\d*}/rounds/{id:[0-9]\\d*}/progress-rate"); + registry.addInterceptor(loginInterceptor()); + } + private HandlerInterceptor loginInterceptor() { + return new PathInterceptor(authInterceptor) + .includePath("/**", ANY) + .excludePath("/login/github/tokens", GET) + .excludePath("/login/tokens/refresh", POST) + .excludePath("/login/fake/tokens", GET) + .excludePath("/members/{id:[0-9]\\d*}", GET) + .excludePath("/members/exists", GET) + .excludePath("/members", GET) + .excludePath("/api/**", GET) + .excludePath("/api-docs/**", GET) + .excludePath("/swagger-ui/**", GET) + .excludePath("/actuator/**", GET) + .excludePath("/fake/proceed", PUT) + .excludePath("/studies", GET) + .excludePath("/studies/{id:[0-9]\\d*}", GET); } @Override diff --git a/backend/src/main/java/com/yigongil/backend/config/auth/AuthInterceptor.java b/backend/src/main/java/com/yigongil/backend/config/auth/AuthInterceptor.java index 017b4093d..3a00187c3 100644 --- a/backend/src/main/java/com/yigongil/backend/config/auth/AuthInterceptor.java +++ b/backend/src/main/java/com/yigongil/backend/config/auth/AuthInterceptor.java @@ -1,7 +1,6 @@ package com.yigongil.backend.config.auth; import com.yigongil.backend.exception.InvalidTokenException; -import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; @@ -11,8 +10,6 @@ @Component public class AuthInterceptor implements HandlerInterceptor { - private static final Pattern STUDY_DETAIL_REQUEST_PATTERN = Pattern.compile("/studies/[1-9]\\d*"); - private final JwtTokenProvider jwtTokenProvider; private final AuthContext authContext; @@ -24,9 +21,6 @@ public AuthInterceptor(JwtTokenProvider jwtTokenProvider, AuthContext authContex @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); - if (isExcludedMethodAndUri(request)) { - return true; - } if (authHeader == null) { throw new InvalidTokenException("인증 정보가 없습니다. 입력된 token: ", null); @@ -35,14 +29,4 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons authContext.setMemberId(memberId); return true; } - - private boolean isExcludedMethodAndUri(HttpServletRequest request) { - if (request.getMethod().equals("GET") && STUDY_DETAIL_REQUEST_PATTERN.matcher(request.getRequestURI()).matches()) { - return true; - } - if (request.getMethod().equals("GET") && request.getRequestURI().equals("/studies")) { - return true; - } - return false; - } } diff --git a/backend/src/main/java/com/yigongil/backend/config/auth/path/HttpMethod.java b/backend/src/main/java/com/yigongil/backend/config/auth/path/HttpMethod.java new file mode 100644 index 000000000..1115fb9f0 --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/config/auth/path/HttpMethod.java @@ -0,0 +1,20 @@ +package com.yigongil.backend.config.auth.path; + +public enum HttpMethod { + + PUT, + POST, + GET, + PATCH, + DELETE, + ANY { + @Override + public boolean matches(String method) { + return true; + } + }; + + public boolean matches(String method) { + return name().equalsIgnoreCase(method); + } +} diff --git a/backend/src/main/java/com/yigongil/backend/config/auth/path/PathContainer.java b/backend/src/main/java/com/yigongil/backend/config/auth/path/PathContainer.java new file mode 100644 index 000000000..dff9a691e --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/config/auth/path/PathContainer.java @@ -0,0 +1,36 @@ +package com.yigongil.backend.config.auth.path; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; + +public class PathContainer { + + private final PathMatcher pathMatcher = new AntPathMatcher(); + private final List includedPaths = new ArrayList<>(); + private final List excludedPaths = new ArrayList<>(); + + public PathContainer excludePath(String path, HttpMethod... httpMethods) { + excludedPaths.add(new PathPattern(path, Set.of(httpMethods))); + + return this; + } + + public PathContainer includePath(String path, HttpMethod... httpMethods) { + includedPaths.add(new PathPattern(path, Set.of(httpMethods))); + + return this; + } + + public boolean isNotInclude(String path, String method) { + boolean isExcludedPath = excludedPaths.stream() + .anyMatch(pathPattern -> pathPattern.matches(pathMatcher, path, method)); + + boolean isNotIncludePath = includedPaths.stream() + .noneMatch(pathPattern -> pathPattern.matches(pathMatcher, path, method)); + + return isExcludedPath || isNotIncludePath; + } +} diff --git a/backend/src/main/java/com/yigongil/backend/config/auth/path/PathInterceptor.java b/backend/src/main/java/com/yigongil/backend/config/auth/path/PathInterceptor.java new file mode 100644 index 000000000..711f59305 --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/config/auth/path/PathInterceptor.java @@ -0,0 +1,39 @@ +package com.yigongil.backend.config.auth.path; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.springframework.web.servlet.HandlerInterceptor; + +public class PathInterceptor implements HandlerInterceptor { + + private final PathContainer pathContainer = new PathContainer(); + private final HandlerInterceptor handlerInterceptor; + + public PathInterceptor(HandlerInterceptor handlerInterceptor) { + this.handlerInterceptor = handlerInterceptor; + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + String method = request.getMethod(); + String uri = request.getRequestURI(); + + if (pathContainer.isNotInclude(uri, method)) { + return true; + } + + return handlerInterceptor.preHandle(request, response, handler); + } + + public PathInterceptor includePath(String path, HttpMethod... methods) { + pathContainer.includePath(path, methods); + + return this; + } + + public PathInterceptor excludePath(String path, HttpMethod... methods) { + pathContainer.excludePath(path, methods); + + return this; + } +} diff --git a/backend/src/main/java/com/yigongil/backend/config/auth/path/PathPattern.java b/backend/src/main/java/com/yigongil/backend/config/auth/path/PathPattern.java new file mode 100644 index 000000000..dd16a62fd --- /dev/null +++ b/backend/src/main/java/com/yigongil/backend/config/auth/path/PathPattern.java @@ -0,0 +1,24 @@ +package com.yigongil.backend.config.auth.path; + +import java.util.Set; +import org.springframework.util.PathMatcher; + +public class PathPattern { + + private final String path; + private final Set httpMethods; + + public PathPattern(String path, Set httpMethods) { + this.path = path; + this.httpMethods = httpMethods; + } + + public boolean matches(PathMatcher pathMatcher, String targetPath, String pathMethod) { + return pathMatcher.match(path, targetPath) && matchesMethod(pathMethod); + } + + private boolean matchesMethod(String pathMethod) { + return httpMethods.stream() + .anyMatch(httpMethod -> httpMethod.matches(pathMethod)); + } +}