在大部分项目中,都存在权限控制,基本上大部分的接口都需要用户的登录信息。现在主流的采用如jwt或者其他方式,来通过请求时向header加入token,然后服务端解析token。所以我们需要在swagger生成的接口文档上也要进行header控制,除了接口参数以外,还要输入token header。
这里提供swagger header三种方式:
一、在每个controller接口上,标记swagger注解完成(@ApiImplicitParam)
@ApiImplicitParam 指定一个请求参数的配置信息,对接口参数进行配置。他有几个属性如下:
name:参数名
value:参数的说明、解释
required:参数是否必须传,默认false
paramType:参数放在哪个地方
· header --> 请求头
· query --> 一般urlcode中的“key=value”,也就是相当于@RequestParam标记的参数
· path --> get请求url中的“/{userId}” ,也就是相当于@PathVariable标记的参数
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer" 等
defaultValue:参数的默认值
@ApiImplicitParams:用在请求的方法上,包含一组参数说明,用于多个@ApiImplicitParam注解时。
1、header中包含userId值,get接口入参 key,都用@ApiImplicitParam注解表示如下:
@ApiOperation(value = "获取西工大学校信息", notes = "该接口负责从项目配置中取出西工大的相关信息")
@ApiImplicitParams({
@ApiImplicitParam(paramType = "header", name = "userId", value = "登录用户id", dataType = "Integer", required = false),
@ApiImplicitParam(paramType = "query", name = "key", value = "关键字", dataType = "Integer", required = true)
})
@GetMapping("/nwpu")
public NwpuVO getNwpuInfo(@RequestParam String key) {
return new NwpuVO(schoolService.getNwpuInfo());
}
2、其中get接口入参key也可以@ApiParam表示(如果没有接口入参,可以去掉),header还是@ApiImplicitParam注解标记:
@ApiOperation(value = "获取西工大学校信息", notes = "该接口负责从项目配置中取出西工大的相关信息")
@ApiImplicitParam(paramType = "header", name = "userId", value = "登录用户id", dataType = "Integer", required = false)
@GetMapping("/nwpu")
public NwpuVO getNwpuInfo(@ApiParam(name = "key", value = "关键字", required = true) @RequestParam String key) {
return new NwpuVO(schoolService.getNwpuInfo());
}
如上方式,效果均如下图:
二、添加为全局参数
针对采用swagger配置类的方式配置swagger情况下,可在swagger配置类中进行header控制,因为大部分的接口都需要token header,所以可以将其作为全局参数配置每一个在swagger接口上。
ParameterBuilder为SpringFox项目中的参数构造器,可以用来构造接口参数,一种工厂模型,可直接构造方法初始化属性,也可分别set。其中部分api说明如下:
和@ApiImplicitParam 的属性含义基本一致:
name:指定参数名
description:参数的说明、描述解释
required:参数是否必须传,默认false
parameterType:参数放在哪个地方
· header --> 请求头
· query --> 一般urlcode中的“key=value”,也就是相当于@RequestParam标记的参数
· path --> get请求url中的“/{userId}” ,也就是相当于@PathVariable标记的参数
· body(不常用)
· form(不常用)
modelRef:指定参数引用类型,String,Integer等
defaultValue:参数的默认值
代码如下:
@Configuration
@EnableSwagger2
public class SwaggerConfig {
private String SCAN_BASE_PACKAGE = "cn.code";
private String VERSION = "1.0.0";
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 标题
.title("Server API")
// 描述
.description("API文档")
// 条款地址(公司内部使用无需配置)
.termsOfServiceUrl("")
// 接口(文档)版本
.version(VERSION)
.build();
}
@Bean
public Docket apiDocket() {
// 全局参数
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name("userId").description("token userId").modelRef(new ModelRef("string"))
.parameterType("header").required(true).build();
pars.add(tokenPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.groupName("RestfulApi")
.select()
// 包扫描范围(对指定的包下进行扫描,如果标注有相关swagger注解,则生成相应文档)
.apis(RequestHandlerSelectors.basePackage(SCAN_BASE_PACKAGE))
// 过滤掉哪些path不用生成swagger
.paths(PathSelectors.any())
.build()
// 忽略该参数在swagger上的显示
.ignoredParameterTypes()
.apiInfo(apiInfo())
// 指定全局参数
.globalOperationParameters(pars)
// swagger生效
.enable(true);
}
}
效果如下图,所有接口上均有该全局参数:
三、无需每个swagger接口上显示该参数,避免重复输入参数
上面两种方式存在一个共同的问题,就是每个swagger接口上均有该参数,每个接口都需要输入一遍,一种重复性的操作。同时第二种方式,设置全局参数,还存在一个问题,就是这种方式会造成每个swagger接口上均有该参数,但实际项目中可能有些接口是不需要该参数的。拿token header举例,对于登录接口就不需要。上面这种方式要解决这个问题的话,需要进行一些额外的操作,很麻烦。所以我们希望,只用在一个地方输入指定了该参数,需要该参数的接口都不需要在额外输入了,这样更方便快捷,并且不需要的地方可以自动过滤。
实现如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Description:swagger配置类
* @Author:
* @Date: 2019-11-18
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
private String SCAN_BASE_PACKAGE = "cn.susoncloud";
private String VERSION = "1.0.0";
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
// 标题
.title("Server API")
// 描述
.description("API文档")
// 条款地址(公司内部使用无需配置)
.termsOfServiceUrl("")
// 接口(文档)版本
.version(VERSION)
.build();
}
@Bean
public Docket apiDocket() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("RestfulApi")
.select()
// 包扫描范围(对指定的包下进行扫描,如果标注有相关swagger注解,则生成相应文档)
.apis(RequestHandlerSelectors.basePackage(SCAN_BASE_PACKAGE))
// 过滤掉哪些path不用生成swagger
.paths(PathSelectors.any())
.build()
// 忽略该参数在swagger上的显示
.ignoredParameterTypes()
// 配置swagger接口安全校验规则
.securitySchemes(securitySchemes())
// 配置swagger接口安全校验上下文中的信息(包含安全权限与安全校验生效的接口路径)
.securityContexts(securityContexts())
.apiInfo(apiInfo())
// swagger生效
.enable(true);
}
private List<ApiKey> securitySchemes() {
return new ArrayList<ApiKey>(){{
add(new ApiKey("userId", "userId", "header"));
}};
}
private List<SecurityContext> securityContexts() {
return new ArrayList<SecurityContext>(){{
add(SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.any())
.build());
}};
}
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return Arrays.asList(
new SecurityReference("userId", authorizationScopes));
}
}
效果图如下:在swagger-ui上会显示一个Authorize按钮,点开,可以看到需要添加的接口认证参数,也就是上述代码中指定的header userId。在未添加的情况下,可以看到接口会有红色感叹号,添加后,会变成蓝色进行提示。这里注意添加与不添加均可以访问接口,接口鉴权通不通过就取决于内部接口逻辑了。如果不填Authorize的话,接口就不会传入 header userId。
填写Authorize后的接口访问