320x100
320x100
일단 Swagger는 Springfox-swagger 2.x 3.x버전과 Springdocs-OpenAPI 두개의 버전이 있습니다!
둘다 사용하는 Bean이 다른데요.
위처럼 TEST-API / 인증이 필요한 API / 인증이 불필요한 API 이렇게 그룹화를 할 수 있습니다.
TEST-API에는 공통적으로 쓰이는 API를 두면 좋겠죠?(ComponentScan 등으로 부모 프로젝트의 특정 패키지를 가리켜주면 됩니다
1. Springfox Swagger 3.0
implementation 'io.springfox:springfox-boot-starter:3.0.0'
# SwaggerConfig.java
package com.boki.realworld.config;
import com.boki.realworld.resolver.LoginUser;
import com.boki.realworld.resolver.OptionalUser;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.function.Predicate;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestAttribute;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
@RequiredArgsConstructor
@Configuration
public class SwaggerConfig {
private final ServerProperties serverProperties;
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.groupName("TEST-API")
.apiInfo(apiInfo())
.securitySchemes(List.of(apiKey()))
.select()
.apis(RequestHandlerSelectors.basePackage("com.boki.realworld.api.test"))
.paths(PathSelectors.any())
.build()
.ignoredParameterTypes(LoginUser.class, OptionalUser.class, RequestAttribute.class)
.useDefaultResponseMessages(false);
}
private ApiInfo apiInfo() {
Integer port = serverProperties.getPort();
return new ApiInfoBuilder()
.title("RealWorld Swagger Open API Docs")
.description(
"<a href=\"http://localhost:" + port
+ "/swagger-ui/index.html#/\" target=\"_self\">Boki's RealWorld API Specification</a>")
.version("1.0")
.termsOfServiceUrl("http://swagger.io/terms/")
.contact(new Contact("boki", "https://code-boki.tistory.com/", "lsb530@naver.com"))
.build();
}
private SecurityContext securityContext() {
return SecurityContext.builder()
.securityReferences(defaultAuth())
.build();
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global",
"accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return List.of(new SecurityReference("Authorization", authorizationScopes));
}
private ApiKey apiKey() {
return new ApiKey("Authorization", "Authorization", "header");
}
public static Predicate<RequestHandler> withoutMethodAnnotation(
final Class<? extends Annotation> annotation) {
return input -> !input.isAnnotatedWith(annotation);
}
@Bean
public Docket NonRequireSecurityApi() {
return new Docket(DocumentationType.OAS_30)
.groupName("NonRequireSecurityApi")
.apiInfo(noAuthApiInfo())
.select()
.apis(withoutMethodAnnotation(PreAuthorize.class))
.paths(PathSelectors.any())
.build()
.ignoredParameterTypes(LoginUser.class, OptionalUser.class, RequestAttribute.class)
.useDefaultResponseMessages(false);
}
@Bean
public Docket RequireSecurityApi() {
return new Docket(DocumentationType.OAS_30)
.groupName("RequireSecurityApi")
.apiInfo(requireAuthApiInfo())
.securityContexts(List.of(securityContext()))
.securitySchemes(List.of(apiKey()))
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(PreAuthorize.class))
.paths(PathSelectors.any())
.build()
.ignoredParameterTypes(LoginUser.class, OptionalUser.class, RequestAttribute.class)
.useDefaultResponseMessages(false);
}
private ApiInfo noAuthApiInfo() {
return new ApiInfoBuilder()
.title("API Specs Without Auth")
.description("<h2>인증이 필요하지 않은 Api 목록들</h2>")
.version("1.0")
.termsOfServiceUrl("http://swagger.io/terms/")
.contact(new Contact("boki", "https://code-boki.tistory.com/", "lsb530@naver.com"))
.build();
}
private ApiInfo requireAuthApiInfo() {
return new ApiInfoBuilder()
.title("API Specs With Auth")
.description("<h2>인증이 필요한 Api 목록들<h2>")
.termsOfServiceUrl("http://swagger.io/terms/")
.contact(new Contact("boki", "https://code-boki.tistory.com/", "lsb530@naver.com"))
.build();
}
}
# Controller
@SecurityRequirement(name = "Authorization")
@GetMapping("/test")
public ResponseEntity<Object> test() {
return ResponseEntity.ok("test!!");
}
@PreAuthorize("isAnonymous()")
@GetMapping("/test0")
public String test0() {
return "test0";
}
@PreAuthorize("isAuthenticated()")
@GetMapping("/test1")
public String test1() {
return "test1";
}
@PreAuthorize("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
@GetMapping("/test2")
public String test2() {
return "test2";
}
SecurityReference 이름을 Authorization으로 만들었기 때문에 인증(자물쇠)이 필요한 요청에 한해서는
@SecurityRequirement(name = "설정")을 붙여줘야된다
2. Springdoc-openapi
implementation 'org.springdoc:springdoc-openapi-ui:1.6.6'
# SwaggerConfig.java
@Bean
public GroupedOpenApi testApi() {
return GroupedOpenApi.builder()
.group("TEST-API")
.packagesToScan("com.boki.realworld.api.test")
.build();
}
@Bean
public GroupedOpenApi nonTestApi() {
return GroupedOpenApi.builder()
.group("API")
.packagesToExclude("com.boki.realworld.api.test")
.build();
}
@Bean
public OpenAPI openAPI() {
Info info = new Info().title("").version("1")
.description("")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact().name("boki").email("lsb530@naver.com"))
.license(new License().name("").url(""));
return new OpenAPI()
.info(info)
.components(new Components()
.addSecuritySchemes("Authorization", new SecurityScheme()
.type(SecurityScheme.Type.APIKEY)
.in(SecurityScheme.In.HEADER)
.name("Authorization")))
.addSecurityItem(new SecurityRequirement().addList("Authorization"));
}
다음번에는 RestDocs로 돌아오겠다!! 안녕
320x100
댓글