Spring Boot 集成 Swagger2 很简单,由于接口采用了OAuth2.0 & JWT 协议做了安全验证,使用过程中也遇到了很多小的问题,多次尝试下述配置可以正常使用。
Maven
<!-- swagger2 --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-bean-validators</artifactId> <version>2.8.0</version> </dependency>
Swagger2Configuration@Configuration @EnableSwagger2 public class Swagger2Configuration { // @Value("${config.oauth2.accessTokenUri}") private String accessTokenUri ="http://localhost:8080/oauth/token"; private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("API 接口服务") .description("API 接口服务") .termsOfServiceUrl("http://www.cnblogs.com/irving") .version("v1") .license("Apache License Version 2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0") .contact(new Contact("irving","http://www.cnblogs.com/irving","zhouyongtao@outlook.com")) .build(); } @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.holiday.sunweb.controller")) //.apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) .paths(PathSelectors.any()) .build() .securityContexts(Collections.singletonList(securityContext())) .securitySchemes(Arrays.asList(securitySchema(), apiKey(), apiCookieKey())); // .globalOperationParameters( // newArrayList(new ParameterBuilder() // .name("access_token") // .description("AccessToken") // .modelRef(new ModelRef("string")) // .parameterType("query") // .required(true) // .build())); } @Bean public SecurityScheme apiKey() { return new ApiKey(HttpHeaders.AUTHORIZATION, "apiKey", "header"); } @Bean public SecurityScheme apiCookieKey() { return new ApiKey(HttpHeaders.COOKIE, "apiKey", "cookie"); } private OAuth securitySchema() { List<AuthorizationScope> authorizationScopeList = newArrayList(); authorizationScopeList.add(new AuthorizationScope("read", "read all")); authorizationScopeList.add(new AuthorizationScope("write", "access all")); List<GrantType> grantTypes = newArrayList(); GrantType passwordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(accessTokenUri); grantTypes.add(passwordCredentialsGrant); return new OAuth("oauth2", authorizationScopeList, grantTypes); } private SecurityContext securityContext() { return SecurityContext.builder().securityReferences(defaultAuth()) .build(); } private List<SecurityReference> defaultAuth() { final AuthorizationScope[] authorizationScopes = new AuthorizationScope[3]; authorizationScopes[0] = new AuthorizationScope("read", "read all"); authorizationScopes[1] = new AuthorizationScope("trust", "trust all"); authorizationScopes[2] = new AuthorizationScope("write", "write all"); return Collections.singletonList(new SecurityReference("oauth2", authorizationScopes)); } // @Bean // public SecurityConfiguration security() { // return new SecurityConfiguration // ("client", "secret", "", "", "Bearer access token", ApiKeyVehicle.HEADER, HttpHeaders.AUTHORIZATION,""); // } @Bean SecurityConfiguration security() { return SecurityConfigurationBuilder.builder() .clientId("client_test") .clientSecret("secret_test") .realm("test-app-realm") .appName("test-app") .scopeSeparator(",") .additionalQueryStringParams(null) .useBasicAuthenticationWithAccessCodeGrant(false) .build(); } @Bean UiConfiguration uiConfig() { return UiConfigurationBuilder.builder() .deepLinking(true) .displayOperationId(false) .defaultModelsExpandDepth(1) .defaultModelExpandDepth(1) .defaultModelRendering(ModelRendering.EXAMPLE) .displayRequestDuration(false) .docExpansion(DocExpansion.NONE) .filter(false) .maxDisplayedTags(null) .operationsSorter(OperationsSorter.ALPHA) .showExtensions(false) .tagsSorter(TagsSorter.ALPHA) .validatorUrl(null) .build(); } }
UserController@Api(value = "用户接口服务", description = "用户接口服务") @RestController @RequestMapping("/api/v1/users") public class UserController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private UserRepository userRepository; @ApiOperation(value = "查询通过 OAuth2.0 授权后获取的用户信息", notes = "通过 OAuth2.0 授权后获取的用户信息") @GetMapping("/principal") public Principal principal(Principal principal) { return principal; } @ApiOperation(value = "根据用户名查询用户信息", notes = "根据用户名查询用户信息") @GetMapping("/{username}") public BaseMsg GetUserInfoByUserName(@PathVariable String username) { return BaseMsgResponse.success(userRepository.findOneByusername(username)); } @ApiOperation(value = "根据ID删除一个用户", notes = "根据ID删除一个用户") @DeleteMapping("/{id}") public BaseMsg getInfoByName(@PathVariable Integer id) { userRepository.deleteById(id); return BaseMsgResponse.success(); } }
最后访问 http://localhost:8080/swagger-ui.html#/
配置 Resource Owner Password Credentials 模式的 Client
Test
问题:
swagger-2.9.1 /csrf is 404 问题
A:这个问题在 2.9.x 版本中有(https://github.com/springfox/springfox/issues/2603) ,暂时还没有找到好的解决方案,回退到 2.8.0 版本。
配置 ApiKey 后 HTTP 头 Authorization: Bearer {THE TOKEN} 不生效问题
A:2.7.x 版本没有问题(https://github.com/springfox/springfox/issues/1812)
@Bean public SecurityScheme apiKey() { return new ApiKey(HttpHeaders.AUTHORIZATION, "apiKey", "header"); }
后面使用了 OAuth2.0 协议在 2.8.0 版本中无问题。
REFER:
https://springfox.github.io/springfox/docs/current/
https://github.com/springfox/springfox
https://github.com/rrohitramsen/spring-boot-oauth2-jwt-swagger-ui