jwt 수정중

This commit is contained in:
2025-12-04 12:26:18 +09:00
parent 899f86d4a1
commit 18fcc2361e
15 changed files with 128 additions and 73 deletions

View File

@@ -3,6 +3,8 @@ package com.kamco.cd.kamcoback.config;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import io.swagger.v3.oas.models.servers.Server;
import java.util.List;
import org.springframework.context.annotation.Bean;
@@ -13,6 +15,21 @@ public class OpenApiConfig {
@Bean
public OpenAPI kamcoOpenAPI() {
// 🔹 1) SecurityScheme 정의 (Bearer JWT)
SecurityScheme bearerAuth =
new SecurityScheme()
.type(SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.in(SecurityScheme.In.HEADER)
.name("Authorization");
// 🔹 2) SecurityRequirement (기본으로 BearerAuth 사용)
SecurityRequirement securityRequirement = new SecurityRequirement().addList("BearerAuth");
// 🔹 3) Components 에 SecurityScheme 등록
Components components = new Components().addSecuritySchemes("BearerAuth", bearerAuth);
return new OpenAPI()
.info(
new Info()
@@ -32,6 +49,8 @@ public class OpenApiConfig {
new Server().url("https://kamco.dev-api.gs.dabeeo.com").description("개발 서버")
// , new Server().url("https://api.kamco.com").description("운영 서버")
))
.components(new Components());
.components(new Components())
// 🔥 여기 한 줄이 "모든 API 기본적으로 BearerAuth 요구" 의미
.addSecurityItem(securityRequirement);
}
}

View File

@@ -2,6 +2,7 @@ package com.kamco.cd.kamcoback.config;
import com.kamco.cd.kamcoback.auth.CustomAuthenticationProvider;
import com.kamco.cd.kamcoback.auth.JwtAuthenticationFilter;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -11,6 +12,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@Configuration
@EnableWebSecurity
@@ -22,29 +26,39 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable()) // CSRF 보안 기능 비활성화
.sessionManagement(
sm ->
sm.sessionCreationPolicy(
SessionCreationPolicy.STATELESS)) // 서버 세션 만들지 않음 요청은 JWT 인증
.formLogin(form -> form.disable()) // react에서 로그인 요청 관리
.httpBasic(basic -> basic.disable()) // 기본 basic 인증 비활성화 JWT 인증사용
.logout(logout -> logout.disable()) // 기본 로그아웃 비활성화 JWT는 서버 상태가 없으므로 로그아웃 처리 필요 없음
.authenticationProvider(
customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll());
// auth.requestMatchers(
// "/api/auth/signin",
// "/api/auth/refresh",
// "/swagger-ui/**",
// "/v3/api-docs/**") // 로그인 없이 접근가능 url
// .permitAll()
// .anyRequest()
// .authenticated())
// .addFilterBefore(
// jwtAuthenticationFilter,
// UsernamePasswordAuthenticationFilter
// .class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장.
// http.csrf(csrf -> csrf.disable()) // CSRF 보안 기능 비활성화
// .sessionManagement(
// sm ->
// sm.sessionCreationPolicy(
// SessionCreationPolicy.STATELESS)) // 서버 세션 만들지 않음 요청은 JWT 인증
// .formLogin(form -> form.disable()) // react에서 로그인 요청 관리
// .httpBasic(basic -> basic.disable()) // 기본 basic 인증 비활성화 JWT 인증사용
// .logout(logout -> logout.disable()) // 기본 로그아웃 비활성화 JWT는 서버 상태가 없으므로 로그아웃 처리 필요 없음
// .authenticationProvider(
// customAuthenticationProvider) // 로그인 패스워드 비교방식 스프링 기본 Provider 사용안함 커스텀 사용
// .authorizeHttpRequests(
// auth ->
// auth.requestMatchers(
// "/api/auth/signin",
// "/api/auth/refresh",
// "/swagger-ui/**",
// "/v3/api-docs/**")
// .permitAll()
// .anyRequest()
// .authenticated())
// .addFilterBefore(
// jwtAuthenticationFilter,
// UsernamePasswordAuthenticationFilter
// .class) // 요청 들어오면 먼저 JWT 토큰 검사 후 security context 에 사용자 정보 저장.
http.csrf(csrf -> csrf.disable())
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.formLogin(form -> form.disable())
.httpBasic(basic -> basic.disable())
.logout(logout -> logout.disable())
.authenticationProvider(customAuthenticationProvider)
.authorizeHttpRequests(
auth -> auth.anyRequest().permitAll() // 🔥 인증 필요 없음
);
;
return http.build();
@@ -55,4 +69,18 @@ public class SecurityConfig {
throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration(); // CORS 객체 생성
config.setAllowedOriginPatterns(List.of("*")); // 도메인 허용
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
config.setAllowedHeaders(List.of("*")); // 헤더요청 Authorization, Content-Type, X-Custom-Header
config.setAllowCredentials(true); // 쿠키, Authorization 헤더, Bearer Token 등 자격증명 포함 요청을 허용할지 설정
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
/** "/**" → 모든 API 경로에 대해 이 CORS 규칙을 적용 /api/** 같이 특정 경로만 지정 가능. */
source.registerCorsConfiguration("/**", config); // CORS 정책을 등록
return source;
}
}

View File

@@ -0,0 +1,10 @@
package com.kamco.cd.kamcoback.config;
// @Configuration
// @SecurityScheme(
// name = "BearerAuth",
// type = SecuritySchemeType.HTTP,
// scheme = "bearer",
// bearerFormat = "JWT"
// )
public class SwaggerConfig {}

View File

@@ -10,22 +10,11 @@ import org.locationtech.jts.geom.Polygon;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**") // 모든 URL 허용
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.allowCredentials(true);
}
@Bean
public ObjectMapper objectMapper() {
SimpleModule module = new SimpleModule();

View File

@@ -9,6 +9,7 @@ import java.util.stream.Collectors;
import org.springframework.web.util.ContentCachingRequestWrapper;
public class ApiLogFunction {
// 클라이언트 IP 추출
public static String getClientIp(HttpServletRequest request) {
String[] headers = {
@@ -34,6 +35,7 @@ public class ApiLogFunction {
// 사용자 ID 추출 예시 (Spring Security 기준)
public static String getUserId(HttpServletRequest request) {
try {
Object userId = request.getUserPrincipal();
return request.getUserPrincipal() != null ? request.getUserPrincipal().getName() : null;
} catch (Exception e) {
return null;
@@ -45,8 +47,12 @@ public class ApiLogFunction {
String uri = request.getRequestURI().toLowerCase();
// URL 기반 DOWNLOAD/PRINT 분류
if (uri.contains("/download") || uri.contains("/export")) return EventType.DOWNLOAD;
if (uri.contains("/print")) return EventType.PRINT;
if (uri.contains("/download") || uri.contains("/export")) {
return EventType.DOWNLOAD;
}
if (uri.contains("/print")) {
return EventType.PRINT;
}
// 일반 CRUD
return switch (method) {
@@ -97,7 +103,9 @@ public class ApiLogFunction {
// JSON Body 읽기
public static String getBodyData(ContentCachingRequestWrapper request) {
byte[] buf = request.getContentAsByteArray();
if (buf.length == 0) return null;
if (buf.length == 0) {
return null;
}
try {
return new String(buf, request.getCharacterEncoding());
} catch (UnsupportedEncodingException e) {