diff --git a/src/main/java/com/soongsil/CoffeeChat/config/CorsMvcConfig.java b/src/main/java/com/soongsil/CoffeeChat/config/CorsMvcConfig.java index 85b006e..b10601a 100644 --- a/src/main/java/com/soongsil/CoffeeChat/config/CorsMvcConfig.java +++ b/src/main/java/com/soongsil/CoffeeChat/config/CorsMvcConfig.java @@ -5,19 +5,22 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration -public class CorsMvcConfig implements WebMvcConfigurer { //컨트롤러에서 보내는 데이터를 받을수 있게끔 +public class CorsMvcConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry corsRegistry) { - - corsRegistry.addMapping("/**") //모든 경로에서 매핑 진행 - .exposedHeaders("Set-Cookie") //노출할 헤더값은 쿠키헤더" - .allowedOrigins("https://localhost:3000", "https://cogo.life", "https://coffeego-ssu.web.app", - "http://localhost:8080", "http://localhost:3000") - .allowedMethods("OPTIONS", "GET", "POST", "PUT", "DELETE") - .allowedHeaders("*") - .allowCredentials(true) - .maxAge(3600); + corsRegistry.addMapping("/**") + .allowedOrigins( + "https://localhost:3000", + "http://localhost:8080", + "https://cogo.life", + "https://coffeego-ssu.web.app", + "https://accounts.google.co.kr") + .allowedMethods("OPTIONS", "GET", "POST", "PUT", "DELETE") + .allowedHeaders("*") + .exposedHeaders("Set-Cookie", "Authorization", "loginStatus") + .allowCredentials(true) + .maxAge(3600); } } diff --git a/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java b/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java index aa47793..bdfdeae 100644 --- a/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java +++ b/src/main/java/com/soongsil/CoffeeChat/config/SecurityConfig.java @@ -55,21 +55,23 @@ public RoleHierarchy roleHierarchy() { return hierarchy; } - @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http - .cors(corsCustomizer -> corsCustomizer.configurationSource(request -> { + .cors(cors -> cors.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.setAllowedOrigins(Arrays.asList( + "https://localhost:3000", + "http://localhost:8080", + "https://cogo.life", + "https://coffeego-ssu.web.app", + "https://accounts.google.co.kr" + )); + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); + configuration.setAllowedHeaders(Collections.singletonList("*")); + configuration.setExposedHeaders(Arrays.asList("Set-Cookie", "Authorization", "Access", "loginStatus")); 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 비활성화 @@ -79,10 +81,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint.userService(customOAuth2UserService)) .successHandler(customSuccessHandler)) .authorizeHttpRequests(auth -> auth - .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 모든 OPTIONS 요청에 대해 인증을 요구하지 않음 + .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .requestMatchers("/health-check", "/", "/auth/reissue/**", "/security-check", "/reissue").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(HttpMethod.GET, "/api/v2/mentors/{mentorId}/**").permitAll() + .requestMatchers(HttpMethod.GET, "/api/v2/mentors/part").permitAll() .requestMatchers("/auth/reissue/mobile/**").permitAll() .requestMatchers("/auth/issue/mobile/**").permitAll() .requestMatchers("/api/v2/possibleDates/**").hasAnyRole("MENTOR", "MENTEE") @@ -90,7 +92,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .requestMatchers("/api/v2/applications/**").hasAnyRole("MENTOR", "MENTEE") .anyRequest().authenticated()) .sessionManagement(session -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) // 세션 정책을 STATELESS로 설정 + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class) .addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); @@ -104,106 +106,3 @@ public WebSecurityCustomizer webSecurityCustomizer() { } } - - - -/* -@Configuration -@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\n"+ - "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(Collections.singletonList("http://localhost:3000")); //프론트 서버의 주소 - configuration.setAllowedMethods(Collections.singletonList("*")); //GET, POST, PUT등 모든 요청 허용 - configuration.setAllowCredentials(true); - configuration.setAllowedHeaders(Collections.singletonList("*")); //모든 헤더 허용 - configuration.setMaxAge(3600L); - - configuration.setExposedHeaders( - Collections.singletonList("Set-Cookie")); //우리가 줄 데이터를 웹페이지에서 보이게 하기 - configuration.setExposedHeaders(Collections.singletonList("Authorization")); - - return configuration; - })); - //csrf disable : stateless이기 때문에 끄기 - http - .csrf((auth) -> auth.disable()); - - //From 로그인 방식 disable - http - .formLogin((auth) -> auth.disable()); - - //HTTP Basic 인증 방식 disable - http - .httpBasic((auth) -> auth.disable()); - //특정 필터 이전에 JWTFilter 추가 - - //기본으로 설정되어있는 LogoutFilter 바로 앞에 커스텀한 LogoutFilter 추가 - http - .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class); - http - .addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); - //oauth2로그인 (인증이 완료되면 리소스 서버로부터 데이터를 받아서 OAuth2UserService로 전달) - //로그인 성공시 customSuccessHandler 호출 - http - .oauth2Login((oauth2) -> oauth2 - .userInfoEndpoint((userInfoEndpointConfig) -> userInfoEndpointConfig - .userService(customOAuth2UserService)) - .successHandler(customSuccessHandler) - ); - http - .addFilterBefore(new CustomLogoutFilter(jwtUtil, refreshRepository), LogoutFilter.class); - - //경로별 인가 작업 - http //기본경로 "/" 제외한 나머지는 로그인해야만 사용가능 - .authorizeHttpRequests((auth) -> auth - .requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() //preflight처리 - .requestMatchers("/health-check", "/", "reissue").permitAll() - .requestMatchers("/api/v1/user/**", "auth/**").hasRole("USER") - //.requestMatchers("/api/v1/**").hasAnyRole("MENTEE", "MENTOR") //로그인 제외하면 다 멘티나 멘토 아니면 접근불가 - .requestMatchers("api/v1/possibleDate/**").hasRole("MENTOR") - .requestMatchers("api/v1/mentor/**").hasRole("MENTEE") - .anyRequest().authenticated()); - //세션 설정 : STATELESS (JWT로 인증 인가 사용할 것이므로) - http - .sessionManagement((session) -> session - .sessionCreationPolicy(SessionCreationPolicy.STATELESS)); - 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/oauth2/CustomSuccessHandler.java b/src/main/java/com/soongsil/CoffeeChat/config/oauth2/CustomSuccessHandler.java index 3162404..ee17237 100644 --- a/src/main/java/com/soongsil/CoffeeChat/config/oauth2/CustomSuccessHandler.java +++ b/src/main/java/com/soongsil/CoffeeChat/config/oauth2/CustomSuccessHandler.java @@ -20,8 +20,6 @@ import java.util.Date; import java.util.Iterator; -//로그인이 성공했을 때 받은 데이터들을 바탕으로 JWT발급을 위한 핸들러 -/* @Component public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { private final JWTUtil jwtUtil; @@ -48,125 +46,37 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo Authentication authentication) throws IOException, ServletException { CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal(); - String username = customUserDetails.getUsername(); + String role = authentication.getAuthorities().iterator().next().getAuthority(); - Collection authorities = authentication.getAuthorities(); - Iterator iterator = authorities.iterator(); - GrantedAuthority auth = iterator.next(); - String role = auth.getAuthority(); - - //String accessToken = jwtUtil.createJwt("access", username, role, 600000L); // 10분 - String accessToken = jwtUtil.createJwt("access", username, role, 180000L); // 10분 - System.out.println("accessToken = " + accessToken); - String refreshToken = jwtUtil.createJwt("refresh", username, role, 86400000L); // 24시간 + String accessToken = jwtUtil.createJwt("access", username, role, 600000L); + String refreshToken = jwtUtil.createJwt("refresh", username, role, 86400000L); addRefreshEntity(username, refreshToken, 86400000L); - System.out.println("=====쿠키쿠키====="); - // Refresh 토큰 쿠키에 추가 + // Add Cookies addSameSiteCookie(response, "refresh", refreshToken); - System.out.println("리프레쉬: " + refreshToken); - System.out.println("=====쿠키쿠키====="); - - // loginStatus 쿠키 추가 - if (role.equals("ROLE_USER")) { - addSameSiteCookie(response, "loginStatus", "signup"); - } else if (role.equals("ROLE_MENTEE") || role.equals("ROLE_MENTOR")) { - addSameSiteCookie(response, "loginStatus", "main"); - } + addSameSiteCookie(response, "loginStatus", role.equals("ROLE_USER") ? "signup" : "main"); response.setStatus(HttpStatus.OK.value()); - //response.sendRedirect("http://localhost:8080/swagger-ui/index.html"); //서버 로컬 테스트용 - //response.sendRedirect("https://localhost:3000/callback"); response.sendRedirect("https://coffeego-ssu.web.app/callback"); } private void addSameSiteCookie(HttpServletResponse response, String name, String value) { ResponseCookie responseCookie = ResponseCookie.from(name, value) - .domain("coffeego-ssu.web.app") .httpOnly(true) .secure(true) - .path("/") - .maxAge(24 * 60 * 60) .sameSite("None") - .build(); - - response.addHeader("Set-Cookie", responseCookie.toString()); - } -} - */ -@Component -public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { - private final JWTUtil jwtUtil; - private final RefreshRepository refreshRepository; - - public CustomSuccessHandler(JWTUtil jwtUtil, RefreshRepository refreshRepository) { - this.jwtUtil = jwtUtil; - this.refreshRepository = refreshRepository; - } - - private void addRefreshEntity(String username, String refresh, Long expiredMs) { - Date date = new Date(System.currentTimeMillis() + expiredMs); - - Refresh refreshEntity = new Refresh(); - refreshEntity.setUsername(username); - refreshEntity.setRefresh(refresh); - refreshEntity.setExpiration(date.toString()); - - refreshRepository.save(refreshEntity); - } - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) throws IOException, ServletException { - - CustomOAuth2User customUserDetails = (CustomOAuth2User)authentication.getPrincipal(); - - String username = customUserDetails.getUsername(); - - Collection authorities = authentication.getAuthorities(); - Iterator iterator = authorities.iterator(); - GrantedAuthority auth = iterator.next(); - String role = auth.getAuthority(); - - //String accessToken = jwtUtil.createJwt("access", username, role, 600000L); // 10분 - String accessToken = jwtUtil.createJwt("access", username, role, 180000L); // 10분 - System.out.println("accessToken = " + accessToken); - String refreshToken = jwtUtil.createJwt("refresh", username, role, 86400000L); // 24시간 - - addRefreshEntity(username, refreshToken, 86400000L); - - // Refresh 토큰 쿠키에 추가 - addSameSiteCookie(response, "refresh", refreshToken); - - // loginStatus 쿠키 추가 - if (role.equals("ROLE_USER")) { - addSameSiteCookie(response, "loginStatus", "signup"); - } else if (role.equals("ROLE_MENTEE") || role.equals("ROLE_MENTOR")) { - addSameSiteCookie(response, "loginStatus", "main"); - } - - response.setStatus(HttpStatus.OK.value()); - //response.sendRedirect("http://localhost:8080/swagger-ui/index.html"); //서버 로컬 테스트용 - //response.sendRedirect("https://localhost:3000/callback"); - response.sendRedirect("https://coffeego-ssu.web.app/callback"); - } - - private void addSameSiteCookie(HttpServletResponse response, String name, String value) { - ResponseCookie responseCookie = ResponseCookie.from(name, value) - .httpOnly(true) - .secure(true) - .maxAge(24 * 60 * 60) .domain(".coffeego-ssu.web.app") .path("/") - .sameSite("None") + .maxAge(24 * 60 * 60) .build(); response.addHeader("Set-Cookie", responseCookie.toString()); } } + /* package com.soongsil.CoffeeChat.config.oauth2;