Swagger와 JWT로 Spring Boot API 보안화
Spring Boot 프로젝트에서 springdoc(OpenAPI) 기반 Swagger와 JWT를 통합해 API 문서에 인증 정보를 반영하고 보안을 강화하는 설정·구성·코드 예시 모음
목차
개요
API 문서를 통해 개발자와 소비자가 동일한 인증 방식을 이해하도록 만드는 것은 중요하다. 특히 JWT를 사용한 인증을 도입하면, 문서화 단계에서 인증 스키마를 명확히 정의해야 실제 테스트와 연동이 매끄럽다. 이 글은 springdoc(OpenAPI) 기반 Swagger와 JWT를 통합하여 Spring Boot에서 안전하게 API를 문서화하는 방법을 소개한다.
필요한 의존성
Maven 의존성
springdoc-openapi와 Spring Security, JWT 라이브러리를 포함한다.
<dependencies>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
</dependencies>
애플리케이션 설정
application.yml 예시
토큰 만료 시간, 시크릿 키 등 JWT 관련 설정을 분리해서 관리한다.
jwt:
secret: my-very-secret-key
expiration-ms: 3600000
springdoc:
api-docs:
path: /v3/api-docs
swagger-ui:
path: /swagger-ui.html
OpenAPI에 JWT 보안 스키마 추가
springdoc에 SecurityScheme과 SecurityRequirement를 등록하면 Swagger UI에 인증 입력 창이 생성된다. 이를 통해 토큰을 입력하면 보호된 엔드포인트를 호출해볼 수 있다.
OpenAPI 설정 클래스
@org.springframework.context.annotation.Configuration
public class OpenApiConfig {
@org.springframework.context.annotation.Bean
public io.swagger.v3.oas.models.OpenAPI customOpenAPI() {
var securityScheme = new io.swagger.v3.oas.models.security.SecurityScheme()
.type(io.swagger.v3.oas.models.security.SecurityScheme.Type.HTTP)
.scheme("bearer")
.bearerFormat("JWT")
.in(io.swagger.v3.oas.models.security.SecurityScheme.In.HEADER)
.name("Authorization");
var securityRequirement = new io.swagger.v3.oas.models.security.SecurityRequirement()
.addList("bearerAuth");
return new io.swagger.v3.oas.models.OpenAPI()
.addSecurityItem(securityRequirement)
.components(new io.swagger.v3.oas.models.Components().addSecuritySchemes("bearerAuth", securityScheme))
.info(new io.swagger.v3.oas.models.info.Info().title("API")
.version("v1")
.description("JWT 인증 통합 API"));
}
}
스프링 시큐리티 JWT 필터 간단 예시
문서화뿐 아니라 실제 요청 검사도 필요하다. 필터에서 Authorization 헤더를 검사해 SecurityContext를 설정한다.
public class JwtAuthenticationFilter extends org.springframework.web.filter.OncePerRequestFilter {
private final String secret;
public JwtAuthenticationFilter(String secret) {
this.secret = secret;
}
@Override
protected void doFilterInternal(javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response,
javax.servlet.FilterChain filterChain)
throws java.io.IOException, javax.servlet.ServletException {
String header = request.getHeader("Authorization");
if (header != null && header.startsWith("Bearer ")) {
String token = header.substring(7);
// 토큰 검증 로직 (예: jjwt 사용)
// 검증 성공 시 Authentication을 설정
}
filterChain.doFilter(request, response);
}
}
컨트롤러에 보안 요구사항 표기
보호된 컨트롤러나 메서드에 @Operation 어노테이션으로 security 요구를 명시하면 문서에서 더 명확해진다.
@org.springframework.web.bind.annotation.RestController
public class SampleController {
@org.springframework.web.bind.annotation.GetMapping("/api/protected")
@io.swagger.v3.oas.annotations.Operation(
summary = "보호된 API",
security = { @io.swagger.v3.oas.annotations.security.SecurityRequirement(name = "bearerAuth") }
)
public java.util.Map<String,Object> protectedEndpoint() {
return java.util.Map.of("status", "ok");
}
}
테스트와 주의사항
- Swagger UI에서 Authorize 버튼으로 Bearer 토큰을 입력해 보호된 엔드포인트를 호출해본다.
- 토큰 만료와 재발급 흐름을 문서와 실제 코드에서 일치시킨다.
- 개발 환경에서는 시크릿을 노출하지 않도록 별도 프로퍼티 관리 방식을 사용한다.
- 권한(ROLE) 기반 문서화가 필요하다면 Operation에 description을 추가하거나 custom 어노테이션을 활용한다.
결론
springdoc과 JWT를 통합하면 API 소비자가 인증 흐름을 이해하고 실제 토큰으로 테스트할 수 있다. 설정은 비교적 단순하지만, 인증 스키마를 명확히 정의하고 시큐리티 필터와 일관되게 구현하는 것이 관건이다. 이 과정을 통해 API 보안과 사용성 모두 향상될 수 있다.