Bootstrap

Knife4j添加全局请求头Authorization

 最近在项目中使用Knife4j+Sa-Token,之前是将token放在cookies中,现在要放入请求头中,借助

 Knife4j作者的文档实现此功能,参考链接OpenAPI3规范中添加Authorization鉴权请求Header不生效?

使用版本

spring boot版本:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
 </parent>
Knife4j版本
<dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.1.0</version>
</dependency>

添加自定义请求头,并添加前缀,鉴权使用Sa-Token

一、设置拦截器

package com.yhx.common.config;

import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.stp.StpUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * @author: yhx
 * @description 注解式鉴权
 * @date: 2024-06-20 16:54
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        String[] excludePatterns = new String[]{"/api/v1/sys/login",
                "/doc.html/**",
                "/swagger-ui/**",
                "/swagger-ui.html",
                "/v3/api-docs/**",
                "/swagger-resources/**",
                "/webjars/**",
                "/swagger-ui.html/**",
                "/api",
                "/api-docs",
                "/api-docs/**"};
        // 注册 Sa-Token 拦截器,打开注解式鉴权功能
        registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
                .addPathPatterns("/**")
                .excludePathPatterns(excludePatterns);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //配置拦截器访问静态资源
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
    @Bean
    public StpLogic getStpLogicJwt() {
        return new StpLogicJwtForSimple();
    }
}

主要是为了解决Knife4j被拦截器拦截问题

二、添加自定义请求头

package com.yhx.common.config;

import com.google.common.net.HttpHeaders;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: yhx
 * @description
 * @date: 2024-06-21 18:41
 */
@Configuration
public class knife4jConfig {
    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI().info(new Info()
                        .title("自定义项目名")
                        .description("这是一个描述")
                        .version("这是版本号"))
                .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION))
                .components(new Components().addSecuritySchemes(
                                HttpHeaders.AUTHORIZATION,
                                new SecurityScheme()
                                        .name(HttpHeaders.AUTHORIZATION)
                                        .type(SecurityScheme.Type.HTTP)
                                        .scheme("Bearer")
                                        .in(SecurityScheme.In.HEADER)
                                        .bearerFormat("JWT")
                        )
                );
    }
}

需要在接口层面定义使用,如下:

@Operation(security = { @SecurityRequirement(name = HttpHeaders.AUTHORIZATION) })

或者

@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
@Operation(summary = "描述1")
@PostMapping("/description")
public ResponseEntity<ConfigPageParam> description(@ParameterObject ConfigPageParam configPageParam){
    return ResponseEntity.ok(configPageParam);
}

 但是这样过于麻烦,每个接口都需要添加,所以我们可以借助Knife4j作者提供的两个接口来实现不需要手动给每个接口添加

  • GlobalOperationCustomizer:针对Operation级别的全局自定义扩展钩子函数,开发者可以对接口中每一个Operation进行扩展自定义实现,或调整,或修改,或增加扩展都行,Knife4j的部分增强特性就是基于此函数实现。
  • GlobalOpenApiCustomizer:是针对整个OpenAPI级别的,开发者在分组或者分包后,得到的单个OpenAPI实例,开发者可以操纵全局的OpenAPI实例,该OpenAPI对象已经是springdoc解析过的实例对象,例如该issues中的需求,开发者只需要自定义创建新Operation对象,然后通过OpenAPI实例对象进行add添加即可完成此需求。

三、接口自动添加

package com.yhx.common.config;

import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.google.common.net.HttpHeaders;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.customizers.GlobalOperationCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;

import java.util.List;

/**
 * @author: yhx
 * @description 为每个接口添加鉴权
 * @date: 2024-06-24 13:51
 */
@Slf4j
@Component
public class Knife4jOperationCustomizer implements GlobalOperationCustomizer {
    @Override
    public Operation customize(Operation operation, HandlerMethod handlerMethod) {
        List<SecurityRequirement> security = operation.getSecurity();
        if (security == null) {
            security = List.of(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION));
            operation.setSecurity(security);
        }
        return operation;
    }
}

效果

;