leftso 13126 0 2018-04-06 16:12:05

logo-cover-Spring Boot Security Swagger2整合生成安全的在线REST  API文档 SpringMVC也可参考

1.概述

创建REST API时,良好的文档是有帮助的。而且,API中的每一个变化都应该在参考文档中同时描述。手动完成这是一个乏味的操作,因此这个过程的自动化是不可避免的。

在本教程中,我们将看看  Swagger 2的Spring Boot REST Web服务。对于本文,我们将使用Swagger 2规范的  Springfox 实现。如果您对Swagger不熟悉,则应 在继续阅读本文之前访问swagger官网以了解更多信息。
 

2.项目说明

我们在示例中使用的REST服务的创建不在本文的讨论范围之内。如果您已经有合适的项目,请使用它。如果没有,下面的链接是一个很好的开始:

  • 使用Spring 4和Java Config文章构建REST API
  • 构建一个RESTful Web服务

提示:创建Spring Boot REST项目可以参考之前写的Swagger2入门篇


3.添加Maven依赖项

这里我们只说需要额外添加的maven依赖。Spring Boot REST项目本身的依赖决定于您自身的项目,暂时不在讨论之内。上一篇我们使用的swagger 版本为2.6.2这里我们将会使用比较新的2.7.0
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>

提示:现在已经有2.8.0版本。目前存在一些无法汉化的问题。暂不推荐正式项目升级。学习研究即可。

4.将Swagger 2集成到项目中

4.1。Java配置

Swagger的配置主要围绕着  Docket bean。

@Configuration
@EnableSwagger2
public class SwaggerConfig {                                    
    @Bean
    public Docket api() { 
        return new Docket(DocumentationType.SWAGGER_2)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build();                                           
    }
}

Swagger 2通过@ EnableSwagger2 批注启用 。

在定义了Docket bean 之后,其  select()  方法返回一个ApiSelectorBuilder实例,该实例提供了一种控制Swagger公开的端点的方法。

可以使用RequestHandlerSelectorsPathSelectors来配置RequestHandler选择的谓词。使用  任何()  都可以通过Swagger为整个API提供文档。

这种配置足以将Swagger 2集成到现有的Spring Boot项目中。对于其他Spring项目,需要进行一些额外的调整。

4.2。项目不是Spring Boot的配置

如果没有Spring Boot,你无法自动配置资源处理程序。Swagger UI添加了一组资源,您必须将其配置为扩展WebMvcConfigurerAdapter的类的一部分    并使用@EnableWebMvc进行注释  

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("swagger-ui.html")
      .addResourceLocations("classpath:/META-INF/resources/");
 
    registry.addResourceHandler("/webjars/**")
      .addResourceLocations("classpath:/META-INF/resources/webjars/");
}
 

4.3。验证Springfox是否正常工作

要验证Springfox是否正常工作,可以在浏览器中访问以下URL:

​​​​​​​http://localhost:8080/spring-security-rest/api/v2/api-docs

结果是带有大量键值对的JSON响应,这不是非常容易理解的。幸运的是,Swagger 为此提供了Swagger UI

5. Swagger UI

Swagger UI是一个内置的解决方案,使得用户可以更轻松地与Swagger生成的API文档进行交互。

5.1。启用S​​pringfox的Swagger UI

要使用Swagger UI,需要另外一个Maven依赖项:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>
现在,您可以通过访问http://localhost:8080/your-app-root/swagger-ui.html在浏览器中对其进行测试

在我们的例子中,顺便说一下,确切的URL是http://localhost:8080/spring-security-rest/api/swagger-ui.html

结果应该如下所示:
swagger2 UI结果展示
 

5.2。学习Swagger文档

Swagger的回复中列出了您的应用程序中定义的所有控制器。点击其中的任何一个将列出有效的HTTP方法(DELETEGETHEADOPTIONSPATCHPOSTPUT)。

展开每种方法都会提供其他有用的数据,例如响应状态,内容类型和参数列表。也可以使用UI来尝试每种方法。

Swagger与您的代码库同步的能力至关重要。为了演示这一点,你可以添加一个新的控制器到你的应用程序。

@RestController
public class CustomController {
 
    @RequestMapping(value = "/custom", method = RequestMethod.POST)
    public String custom() {
        return "custom";
    }
}
现在,如果刷新Swagger文档,您将在控制器列表中看到自定义控制器。如您所知,Swagger的回复中只显示一种方法(POST)。

6.高级配置

应用程序的Docket bean可以配置为让您更多地控制API文档生成过程。

6.1。过滤Swagger响应的API

公开整个API的文档并不总是可取的。您可以通过将参数传递给Docket类的apis()paths()方法来限制Swagger的响应  。

如上所示,RequestHandlerSelectors允许使用  anynone谓词,但也可用于根据基本包,类注释和方法注释过滤API。

PathSelectors提供了额外的过滤功能,并使用谓词来扫描应用程序的请求路径。你可以使用  any()none(),  regex()或  ant()

在下面的示例中,我们将指示Swagger使用ant()  谓词仅包含特定包中的控制器,并使用特定的路径。
 

@Bean
public Docket api() {                
    return new Docket(DocumentationType.SWAGGER_2)          
      .select()                                       
      .apis(RequestHandlerSelectors.basePackage("org.baeldung.web.controller"))
      .paths(PathSelectors.ant("/foos/*"))                     
      .build();
}

6.2。自定义信息

Swagger还在您的自定义响应中提供了一些默认值,例如“Api文档”,“由联系人电子邮件创建”,“Apache 2.0”。

要更改这些值,可以使用  apiInfo(ApiInfo apiInfo) 方法。包含有关API的自定义信息的  ApiInfo类。

@Bean
public Docket api() {                
    return new Docket(DocumentationType.SWAGGER_2)          
      .select()
      .apis(RequestHandlerSelectors.basePackage("com.example.controller"))
      .paths(PathSelectors.ant("/foos/*"))
      .build()
      .apiInfo(apiInfo());
}
 
private ApiInfo apiInfo() {
     return new ApiInfo(
       "My REST API", 
       "Some custom description of API.", 
       "API TOS", 
       "Terms of service", 
       new Contact("John Doe", "www.example.com", "myeaddress@company.com"), 
       "License of API", "API license URL", Collections.emptyList());
}

6.3。自定义方法响应消息

Swagger允许通过  Docket的  globalResponseMessage()方法全局覆盖HTTP方法的响应消息。首先,您必须指示Swagger不要使用默认响应消息。 

假设您希望覆盖  所有GET方法的500403响应消息。为了达到这个目的,一些代码必须被添加到Docket的初始化块(为了清楚起见,原始冗余代码被排除):

.useDefaultResponseMessages(false)                                   
.globalResponseMessage(RequestMethod.GET,                     
  newArrayList(new ResponseMessageBuilder()   
    .code(500)
    .message("500 message")
    .responseModel(new ModelRef("Error"))
    .build(),
    new ResponseMessageBuilder() 
      .code(403)
      .message("Forbidden!")
      .build()));
swagger  UI 2

7.具有OAuth安全API的Swagger UI

Swagger UI提供了许多非常有用的功能 - 目前为止我们已经介绍了这些功能。但是如果我们的API是安全的并且不可访问的话,我们不能真正使用其中的大部分。

让我们看看我们如何允许Swagger访问OAuth安全的API--在本例中使用授权代码授权类型。

我们将使用SecuritySchemeSecurityContext支持配置Swagger以访问我们的安全API  :

@Bean
public Docket api() {
    return new Docket(DocumentationType.SWAGGER_2).select()
        .apis(RequestHandlerSelectors.any())
        .paths(PathSelectors.any())
        .build()
        .securitySchemes(Arrays.asList(securityScheme()))
        .securityContexts(Arrays.asList(securityContext()));
}

7.1。安全配置

我们将在Swagger配置中定义一个  SecurityConfiguration bean - 并设置一些默认值:

@Bean
public SecurityConfiguration security() {
    return SecurityConfigurationBuilder.builder()
        .clientId(CLIENT_ID)
        .clientSecret(CLIENT_SECRET)
        .scopeSeparator(" ")
        .useBasicAuthenticationWithAccessCodeGrant(true)
        .build();
}
 

7.2。SecurityScheme

接下来,我们将定义我们的SecurityScheme ; 这用于描述我们的API如何保护(基本认证,OAuth2,...)。

在我们的例子中,我们将定义一个用于保护我们的资源服务器的OAuth方案:

private SecurityScheme securityScheme() {
    GrantType grantType = new AuthorizationCodeGrantBuilder()
        .tokenEndpoint(new TokenEndpoint(AUTH_SERVER + "/token", "oauthtoken"))
        .tokenRequestEndpoint(
          new TokenRequestEndpoint(AUTH_SERVER + "/authorize", CLIENT_ID, CLIENT_ID))
        .build();
 
    SecurityScheme oauth = new OAuthBuilder().name("spring_oauth")
        .grantTypes(Arrays.asList(grantType))
        .scopes(Arrays.asList(scopes()))
        .build();
    return oauth;
}

请注意,我们使用了授权码授权类型 - 我们需要为其提供令牌端点以及我们的OAuth2授权服务器的授权URL。

以下是我们需要定义的范围:

private AuthorizationScope[] scopes() {
    AuthorizationScope[] scopes = { 
      new AuthorizationScope("read", "for read operations"), 
      new AuthorizationScope("write", "for write operations"), 
      new AuthorizationScope("foo", "Access foo API") };
    return scopes;
}

这些与我们在应用中实际定义的范围同步/ foos API。

7.3。Security Context

最后,我们需要为我们的示例API定义一个安全上下文:

private SecurityContext securityContext() {
    return SecurityContext.builder()
      .securityReferences(Arrays.asList(new SecurityReference("spring_oauth", scopes())))
      .forPaths(PathSelectors.regex("/foos.*"))
      .build();
}

请注意,我们在此处使用的名称(参考 -  spring_oauth)与我们之前使用的名称在SecurityScheme中同步。

7.4。测试

好吧,现在我们已经准备好了所有的东西,让我们来看看我们的Swagger UI并尝试访问Foo API:

我们可以在本地访问Swagger UI:

1
http://localhost:8082/spring-security-oauth-resource/swagger-ui.html

由于我们的安全配置,我们可以看到现在存在一个新的“授权”按钮:

swagger ui security

当我们点击“授权”按钮时,我们可以看到以下弹出窗口 - 授权我们的Swagger UI访问安全的API:
swagger ui security 2

注意:

  • 我们已经可以看到CLIENT_ID和CLIENT_SECRET了 - 因为我们已经预先配置了它们(但我们仍然可以更改它们)
  • 我们现在可以选择我们需要的范围

以下是安全API的标记方式:
swagger ui  security

 

现在,最后,我们可以打我们的API!
当然,不言而喻,我们需要小心如何在外部公开Swagger UI,因为此安全配置处于活动状态。

8.总结

在本教程中,我们设置了Swagger 2来为Spring REST API生成文档。我们还探索了可视化和自定义Swagger输出的方法。最后,我们查看了Swagger的一个简单的OAuth配置。