阿毛
It's me !
想你所想

Swagger之接口header控制

在大部分项目中,都存在权限控制,基本上大部分的接口都需要用户的登录信息。现在主流的采用如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());
    }

如上方式,效果均如下图:

https://file.blog.humh.cn/2020/06/d2b5ca33bd970f64a6301fa75ae2eb22-14.png

二、添加为全局参数

针对采用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);
    }
}

效果如下图,所有接口上均有该全局参数:

https://file.blog.humh.cn/2020/06/d2b5ca33bd970f64a6301fa75ae2eb22-15.png

三、无需每个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。

https://file.blog.humh.cn/2020/06/d2b5ca33bd970f64a6301fa75ae2eb22-16.png

填写Authorize后的接口访问

https://file.blog.humh.cn/2020/06/d2b5ca33bd970f64a6301fa75ae2eb22-17.png

humh

文章作者

站长本人,一个憨批!

发表回复

textsms
account_circle
email

想你所想

Swagger之接口header控制
在大部分项目中,都存在权限控制,基本上大部分的接口都需要用户的登录信息。现在主流的采用如jwt或者其他方式,来通过请求时向header加入token,然后服务端解析token。所以我们需要在swa…
扫描二维码继续阅读
2020-06-14