From 4f9eb48d930b5a80ff3adc0052b9ef6c20c89d19 Mon Sep 17 00:00:00 2001 From: MinJi Kim Date: Sat, 30 Nov 2024 19:48:25 +0900 Subject: [PATCH] =?UTF-8?q?ref:=20=ED=8C=8C=ED=8A=B8=EB=B3=84=20=EB=A9=98?= =?UTF-8?q?=ED=86=A0=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=A1=B0=ED=9A=8C,?= =?UTF-8?q?=20=EB=A9=98=ED=86=A0=20=EC=83=81=EC=84=B8=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C=20=ED=86=A0=ED=81=B0=20=ED=95=B4=EC=A0=9C?= =?UTF-8?q?=20(#190)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CoffeeChat/config/SecurityConfig.java | 145 +++++++++--------- .../CoffeeChat/config/jwt/JWTFilter.java | 10 +- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java b/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java index cc650c6..4b64839 100644 --- a/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java +++ b/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java @@ -28,78 +28,79 @@ @EnableWebSecurity public class SecurityConfig { - private final CustomOAuth2UserService customOAuth2UserService; - private final CustomSuccessHandler customSuccessHandler; - private final JWTUtil jwtUtil; - private final RefreshRepository refreshRepository; - - public SecurityConfig(CustomOAuth2UserService customOAuth2UserService, - CustomSuccessHandler customSuccessHandler, - JWTUtil jwtUtil, - RefreshRepository refreshRepository) { - this.customOAuth2UserService = customOAuth2UserService; - this.customSuccessHandler = customSuccessHandler; - this.jwtUtil = jwtUtil; - this.refreshRepository = refreshRepository; - } - - @Bean - public RoleHierarchy roleHierarchy() { - RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); - hierarchy.setHierarchy(""" - ROLE_ADMIN > ROLE_MENTEE - ROLE_ADMIN > ROLE_MENTOR - ROLE_MENTEE > ROLE_USER - ROLE_MENTOR > ROLE_USER - """); - return hierarchy; - } - - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http - .cors(corsCustomizer -> corsCustomizer.configurationSource(request -> { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins( - Arrays.asList("https://localhost:3000", "http://localhost:8080", "http://localhost:3000", - "https://cogo.life", "https://coffeego-ssu.web.app")); // 프론트 서버의 주소들 // 프론트 서버의 주소 - configuration.setAllowedMethods(Collections.singletonList("*")); // 모든 요청 메서드 허용 - configuration.setAllowCredentials(true); - configuration.setAllowedHeaders(Collections.singletonList("*")); // 모든 헤더 허용 - configuration.setMaxAge(3600L); - configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "Authorization", "Access", - "loginStatus")); // Set-Cookie 및 Authorization 헤더 노출 - return configuration; - })) - .csrf(csrf -> csrf.disable()) // CSRF 비활성화 - .formLogin(formLogin -> formLogin.disable()) // 폼 로그인 비활성화 - .httpBasic(httpBasic -> httpBasic.disable()) // HTTP Basic 인증 비활성화 - .oauth2Login(oauth2 -> oauth2 - .userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint.userService(customOAuth2UserService)) - .successHandler(customSuccessHandler)) - .authorizeHttpRequests(auth -> auth - .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 모든 OPTIONS 요청에 대해 인증을 요구하지 않음 - .requestMatchers("/health-check", "/", "/auth/reissue/**", "/security-check").permitAll() - .requestMatchers("/api/v2/users/**", "/auth/**").hasRole("USER") - .requestMatchers(("/auth/reissue/mobile/**")).permitAll() - .requestMatchers("/api/v2/possibleDates/**").hasAnyRole("MENTOR", "MENTEE") - .requestMatchers("/api/v2/mentors/**").hasAnyRole("MENTOR", "MENTEE") - .requestMatchers("/api/v2/applications/**").hasAnyRole("MENTOR", "MENTEE") - .anyRequest().authenticated()) - .sessionManagement(session -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 정책을 STATELESS로 설정 - .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class) - .addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); - - return http.build(); - } - - @Bean - public WebSecurityCustomizer webSecurityCustomizer() { - return web -> web.ignoring() - .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**"); - } + private final CustomOAuth2UserService customOAuth2UserService; + private final CustomSuccessHandler customSuccessHandler; + private final JWTUtil jwtUtil; + private final RefreshRepository refreshRepository; + + public SecurityConfig(CustomOAuth2UserService customOAuth2UserService, + CustomSuccessHandler customSuccessHandler, + JWTUtil jwtUtil, + RefreshRepository refreshRepository) { + this.customOAuth2UserService = customOAuth2UserService; + this.customSuccessHandler = customSuccessHandler; + this.jwtUtil = jwtUtil; + this.refreshRepository = refreshRepository; + } + + @Bean + public RoleHierarchy roleHierarchy() { + RoleHierarchyImpl hierarchy = new RoleHierarchyImpl(); + hierarchy.setHierarchy(""" + ROLE_ADMIN > ROLE_MENTEE + ROLE_ADMIN > ROLE_MENTOR + ROLE_MENTEE > ROLE_USER + ROLE_MENTOR > ROLE_USER + """); + return hierarchy; + } + + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .cors(corsCustomizer -> corsCustomizer.configurationSource(request -> { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins( + Arrays.asList("https://localhost:3000", "http://localhost:8080", "http://localhost:3000", + "https://cogo.life", "https://coffeego-ssu.web.app")); // 프론트 서버의 주소들 // 프론트 서버의 주소 + configuration.setAllowedMethods(Collections.singletonList("*")); // 모든 요청 메서드 허용 + configuration.setAllowCredentials(true); + configuration.setAllowedHeaders(Collections.singletonList("*")); // 모든 헤더 허용 + configuration.setMaxAge(3600L); + configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "Authorization", "Access", + "loginStatus")); // Set-Cookie 및 Authorization 헤더 노출 + return configuration; + })) + .csrf(csrf -> csrf.disable()) // CSRF 비활성화 + .formLogin(formLogin -> formLogin.disable()) // 폼 로그인 비활성화 + .httpBasic(httpBasic -> httpBasic.disable()) // HTTP Basic 인증 비활성화 + .oauth2Login(oauth2 -> oauth2 + .userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint.userService(customOAuth2UserService)) + .successHandler(customSuccessHandler)) + .authorizeHttpRequests(auth -> auth + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 모든 OPTIONS 요청에 대해 인증을 요구하지 않음 + .requestMatchers("/health-check", "/", "/auth/reissue/**", "/security-check").permitAll() + .requestMatchers(HttpMethod.GET, "/api/v2/mentors/{mentorId}/**").permitAll() // mentorId로 조회 + .requestMatchers(HttpMethod.GET, "/api/v2/mentors/part").permitAll() // 파트별 조회.requestMatchers("/api/v2/users/**", "/auth/**").hasRole("USER") + .requestMatchers("/auth/reissue/mobile/**").permitAll() + .requestMatchers("/api/v2/possibleDates/**").hasAnyRole("MENTOR", "MENTEE") + .requestMatchers("/api/v2/mentors/**").hasAnyRole("MENTOR", "MENTEE") + .requestMatchers("/api/v2/applications/**").hasAnyRole("MENTOR", "MENTEE") + .anyRequest().authenticated()) + .sessionManagement(session -> session + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 정책을 STATELESS로 설정 + .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class) + .addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); + + return http.build(); + } + + @Bean + public WebSecurityCustomizer webSecurityCustomizer() { + return web -> web.ignoring() + .requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-resources/**"); + } } diff --git a/src/main/java/com/soongsil/CoffeeChat/config/jwt/JWTFilter.java b/src/main/java/com/soongsil/CoffeeChat/config/jwt/JWTFilter.java index 93a8b67..b8d6c41 100644 --- a/src/main/java/com/soongsil/CoffeeChat/config/jwt/JWTFilter.java +++ b/src/main/java/com/soongsil/CoffeeChat/config/jwt/JWTFilter.java @@ -28,7 +28,7 @@ public JWTFilter(JWTUtil jwtUtil) { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { + FilterChain filterChain) throws ServletException, IOException { // 특정 경로들에 대해 필터 로직을 건너뛰도록 설정 if (request.getMethod().equals(HttpMethod.OPTIONS.name())) { @@ -37,7 +37,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse return; } String path = request.getRequestURI(); - if (path.startsWith("/health-check") || path.startsWith("/security-check") || path.startsWith("/auth/reissue")||path.startsWith("/login")) { + if (path.startsWith("/health-check") || path.startsWith("/security-check") + || path.startsWith("/auth/reissue") || path.startsWith("/login") + || path.matches("^/api/v2/mentors/\\d+$") || path.matches("^/api/v2/mentors/part$")) { System.out.println("jwt필터 통과로직"); filterChain.doFilter(request, response); return; @@ -63,7 +65,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 에러 반환 response.setContentType("application/json"); response.getWriter() - .write("{\"error\": \"Access token expired\"}"); //응답 json에 error : access token expired메시지 작성 + .write("{\"error\": \"Access token expired\"}"); //응답 json에 error : access token expired메시지 작성 filterChain.doFilter(request, response); //조건이 해당되면 메소드 종료 (필수) @@ -87,7 +89,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse //스프링 시큐리티 인증 토큰 생성 Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuth2User, null, - customOAuth2User.getAuthorities()); + customOAuth2User.getAuthorities()); //세션에 사용자 등록 SecurityContextHolder.getContext().setAuthentication(authToken);