最近在项目中使用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;
}
}
效果