제품, 카테고리, 사용자에 대한 기본적인 CRUD API만 만들었는데도, API의 수가 많아졌다 이에 이를 간단하게 문서화하여, Frontend 화면을 만드는 친구에게 남기기 위해, 그리고 나 스스로를 위해 (시간 절약,, 👻) Swagger
를 도입해보았다
그 과정에서 Swagger와 Spring Security 설정에서 막히는 부분이 있었는데 이를 해결한 과정을 기록하고자 한다!
API 문서 생성 및 테스트 도구로, Spring Boot 기반의 프로젝트에서 API 문서를 자동으로 생성하고 사용자가 API를 시각적으로 탐색하고 테스트할 수 있도록 도와준다.
Spring 기반 애플리케이션에서 보안을 구현하기 위한 프레임워크로, 인증 및 권한 부여를 관리하는 데 사용된다.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
security:
jwt:
token:
key: {JWT Key}
expire-length: 3600000
springdoc:
swagger-ui:
path: /swagger-ui.html
groups-order: DESC
operationsSorter: method
disable-swagger-default-url: true
display-request-duration: true
defaultModelsExpandDepth: -1
api-docs:
path: /api
show-actuator: true
default-consumes-media-type: application/json
default-produces-media-type: application/json
paths-to-match:
- /**
JWT (Json Web Token)에 대한 인증과 API 엔드포인트에 대한 권한 설정 및 특정 포트에서의 API 호출 허용
[Spring Security]
@Bean
public DefaultSecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> corsConfigurationSource())
.csrf(csrf -> csrf.disable())
.exceptionHandling(req -> req.authenticationEntryPoint(jwtAuthEntryPoint))
.authorizeHttpRequests(authorizeRequests ->
authorizeRequests
.requestMatchers(HttpMethod.POST, "/api/v1/user/login")
.permitAll()
.requestMatchers(CorsUtils::isPreFlightRequest)
.permitAll()
.anyRequest()
.authenticated()
)
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
[CORS 설정]
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:${port}"));
configuration.addAllowedHeader("*");
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PATCH", "DELETE"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
// API 전체 설정
@OpenAPIDefinition(
info = @Info(
title = "Logistics API",
description = "제품, 상점 관리를 위한 인터페이스 규격서",
version = "1.0"
)
)
// API 그룹 정의. 경로가 /인 API에 대한 설정
@Bean
public GroupedOpenApi chatOpenApi() {
String[] paths = { "/" };
return GroupedOpenApi
.builder()
.group("logistics")
.pathsToMatch(paths)
.build();
}
// API 보안 설정
@Bean
public OpenAPI api() {
SecurityScheme apiKey = new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("${name}");
SecurityRequirement securityRequirement = new SecurityRequirement()
.addList("apiKey");
return new OpenAPI()
.components(new Components().addSecuritySchemes("apiKey", apiKey))
.addSecurityItem(securityRequirement);
}
application.yml에 설정한 대로, http://localhost:${port}/swagger-ui/index.html 로 접속한 결과,
익숙하지만 반갑진 않은,,, 알림이 떴다
401 에러였고(the server responded with a status of 401 ()
),
백앤드에서 응답은 했기에 Spring Security 설정에서 Swagger 경로도 API 요청을 허용해 주었다
.requestMatchers(HttpMethod.GET, "/swagger-ui/*")
.permitAll()
그랬더니 이번엔 /swagger-config API를 못 호출한다 (Failed to load remote configuration
) 그래서 역시 config에 해당 경로도 요청 허용해 주었다,,,,
.requestMatchers(HttpMethod.GET, "/api/swagger-config")
.permitAll()
에러는 안좋지만,,, 달라진 에러는 또 괜찮다.. 이번엔 Failed to load API definition
에러가 떴다 그래서 Swagger config에서 설정한 group에 해당하는 (GroupedOpenApi) /api/logistics 경로까지 허용해주었다
.requestMatchers(HttpMethod.GET, "/api/logistics")
.permitAll()
다음과 같은 예쁜 Swagger 페이지를 만들 수 있었다 🌺🌺 지금은 API 껍데기만 만들었으니,, 얼른 문서화해야겠다
Swagger와 Security를 나처럼 동시에 사용해서,, 비슷한 에러를 경험한 사람들에게 도움이 됐으면 좋겠다🌞
Spring Security는 몰랐을때는 당황스럽죠 ㅋㅋㅋ