From 9662eda4bf9e66027a5cbe31f55ab3721aa676ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B2=9C=20=EC=A7=84=EA=B0=95?= <jjjjjk12@ajou.ac.kr> Date: Sat, 29 Mar 2025 13:54:43 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9D=B8=EC=A6=9D=20=EC=9D=B8=ED=84=B0?= =?UTF-8?q?=EC=85=89=ED=84=B0=EC=97=90=EC=84=9C=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=97=90=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{AuthInterceptor.java => AuthFilter.java} | 153 +++++++++--------- .../com/aolda/itda/config/LoggingFilter.java | 15 +- .../java/com/aolda/itda/config/WebConfig.java | 27 +++- 3 files changed, 107 insertions(+), 88 deletions(-) rename src/main/java/com/aolda/itda/config/{AuthInterceptor.java => AuthFilter.java} (71%) diff --git a/src/main/java/com/aolda/itda/config/AuthInterceptor.java b/src/main/java/com/aolda/itda/config/AuthFilter.java similarity index 71% rename from src/main/java/com/aolda/itda/config/AuthInterceptor.java rename to src/main/java/com/aolda/itda/config/AuthFilter.java index fd78fb6..f810c2c 100644 --- a/src/main/java/com/aolda/itda/config/AuthInterceptor.java +++ b/src/main/java/com/aolda/itda/config/AuthFilter.java @@ -1,77 +1,76 @@ -package com.aolda.itda.config; - -import com.aolda.itda.dto.auth.IdAndNameDTO; -import com.aolda.itda.exception.CustomException; -import com.aolda.itda.exception.ErrorCode; -import com.aolda.itda.service.AuthService; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import org.springframework.web.servlet.HandlerInterceptor; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -@RequiredArgsConstructor -@Component -@Slf4j -public class AuthInterceptor implements HandlerInterceptor { - - private final AuthService authService; - - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { - String token = request.getHeader("X-Subject-Token"); - - /* 토큰 헤더 검증 */ - if (token == null || token.isEmpty()) { - throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI()); - } - - /* 유효 토큰 검증 */ - String userId = authService.validateTokenAndGetUserId(token); - if (userId == null) { - log.error("Token validation failed for URI {}: {}", request.getRequestURI(), request.getRemoteAddr()); - throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI()); - } - - /* 프로젝트 권한 검증 */ - String projectId = request.getParameter("projectId"); - if (projectId != null) { - - try { - authService.getBestRoleWithinProject(token, projectId).get("role"); - if (!request.getMethod().equals("GET") && !authService.getBestRoleWithinProject(token, projectId).get("role").equals("admin")) { - throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI()); - - } - } catch (Exception e) { - throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI()); - } - - - - } - - /* 프로젝트 리스트 조회 */ - List<String> projects; - if (authService.isAdmin(Map.of("id", userId, "token", token))) { - projects = authService.getAllProjects(token).stream().map(IdAndNameDTO::getId) - .toList(); - } - - else { - projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token)) - .stream().map(IdAndNameDTO::getId) - .toList(); - } - - request.setAttribute("projects", projects); - request.setAttribute("user", Map.of("id", userId, "token", token)); - return true; - - } -} +package com.aolda.itda.config; + +import com.aolda.itda.dto.auth.IdAndNameDTO; +import com.aolda.itda.exception.CustomException; +import com.aolda.itda.exception.ErrorCode; +import com.aolda.itda.service.AuthService; +import jakarta.servlet.FilterChain; +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.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +@RequiredArgsConstructor +@Component +@Slf4j +public class AuthFilter extends OncePerRequestFilter { + + private final AuthService authService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + if (request.getRequestURI().contains("/api/auth")) { + filterChain.doFilter(request, response); + return; + } + + String token = request.getHeader("X-Subject-Token"); + + // 토큰 헤더 검증 + if (token == null || token.isEmpty()) { + throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI()); + } + + // 유효 토큰 검증 + String userId = authService.validateTokenAndGetUserId(token); + if (userId == null) { + log.error("Token validation failed for URI {}: {}", request.getRequestURI(), request.getRemoteAddr()); + throw new CustomException(ErrorCode.INVALID_TOKEN, request.getRequestURI()); + } + + // 프로젝트 권한 검증 + String projectId = request.getParameter("projectId"); + if (projectId != null) { + try { + authService.getBestRoleWithinProject(token, projectId).get("role"); + if (!request.getMethod().equals("GET") && !authService.getBestRoleWithinProject(token, projectId).get("role").equals("admin")) { + throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI()); + } + } catch (Exception e) { + throw new CustomException(ErrorCode.UNAUTHORIZED_USER, request.getRequestURI()); + } + } + + // 프로젝트 리스트 조회 + List<String> projects; + if (authService.isAdmin(Map.of("id", userId, "token", token))) { + projects = authService.getAllProjects(token).stream().map(IdAndNameDTO::getId).toList(); + } else { + projects = authService.getProjectsWithUser(Map.of("id", userId, "token", token)).stream().map(IdAndNameDTO::getId).toList(); + } + + request.setAttribute("projects", projects); + request.setAttribute("user", Map.of("id", userId, "token", token)); + + filterChain.doFilter(request, response); + } +} \ No newline at end of file diff --git a/src/main/java/com/aolda/itda/config/LoggingFilter.java b/src/main/java/com/aolda/itda/config/LoggingFilter.java index f2330bf..8c5c2f0 100644 --- a/src/main/java/com/aolda/itda/config/LoggingFilter.java +++ b/src/main/java/com/aolda/itda/config/LoggingFilter.java @@ -1,9 +1,14 @@ package com.aolda.itda.config; +import com.aolda.itda.exception.CustomException; +import com.aolda.itda.exception.ErrorCode; +import com.aolda.itda.service.AuthService; +import com.fasterxml.jackson.core.JsonProcessingException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @@ -11,11 +16,14 @@ import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.util.ContentCachingRequestWrapper; import java.io.IOException; +import java.util.Map; @Component +@RequiredArgsConstructor public class LoggingFilter extends OncePerRequestFilter { private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class); + private final AuthService authService; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) @@ -29,15 +37,16 @@ public class LoggingFilter extends OncePerRequestFilter { logRequest(cachingRequest); } - private void logRequest(ContentCachingRequestWrapper request) { + private void logRequest(ContentCachingRequestWrapper request) throws JsonProcessingException { String ip = request.getRemoteAddr(); String method = request.getMethod(); String uri = request.getRequestURI(); String queryString = request.getQueryString(); String body = getRequestBody(request); + Map<String, String> user = (Map<String, String>) request.getAttribute("user"); - logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, Request Body: {}", - ip, method, uri, (queryString != null ? queryString : "None"), + logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, User: {}, Request Body: {}", + ip, method, uri, (queryString != null ? queryString : "None"), (user != null ? user.get("id") : "None"), (!body.isEmpty() ? body : "None")); } diff --git a/src/main/java/com/aolda/itda/config/WebConfig.java b/src/main/java/com/aolda/itda/config/WebConfig.java index e3893ae..a3559c4 100644 --- a/src/main/java/com/aolda/itda/config/WebConfig.java +++ b/src/main/java/com/aolda/itda/config/WebConfig.java @@ -3,17 +3,18 @@ package com.aolda.itda.config; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import lombok.RequiredArgsConstructor; +import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @RequiredArgsConstructor public class WebConfig implements WebMvcConfigurer { - private final AuthInterceptor authInterceptor; + private final AuthFilter authFilter; + private final LoggingFilter loggingFilter; @Override public void addCorsMappings(CorsRegistry registry) { // 스프링단에서 cors 설정 @@ -26,13 +27,23 @@ public class WebConfig implements WebMvcConfigurer { ; } - @Override - public void addInterceptors(InterceptorRegistry registry) { - String[] excludeAuth = {"/error", "/api/auth/*" }; - registry.addInterceptor(authInterceptor) - .addPathPatterns("/**") - .excludePathPatterns(excludeAuth); + @Bean + public FilterRegistrationBean<AuthFilter> authFilterRegistration() { + FilterRegistrationBean<AuthFilter> registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(authFilter); + registrationBean.setOrder(1); // AuthFilter의 순서를 1로 설정 + registrationBean.addUrlPatterns("/*"); + return registrationBean; + } + + @Bean + public FilterRegistrationBean<LoggingFilter> loggingFilterRegistration() { + FilterRegistrationBean<LoggingFilter> registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(loggingFilter); + registrationBean.setOrder(2); // LoggingFilter의 순서를 2로 설정 + registrationBean.addUrlPatterns("/*"); + return registrationBean; } @Bean -- GitLab