|
@@ -2,18 +2,25 @@ package cc.uncarbon.framework.knife4j.config;
|
|
|
|
|
|
|
|
import cc.uncarbon.framework.core.props.HelioProperties;
|
|
import cc.uncarbon.framework.core.props.HelioProperties;
|
|
|
import cc.uncarbon.framework.knife4j.customizer.HelioBaseEnumCustomizer;
|
|
import cc.uncarbon.framework.knife4j.customizer.HelioBaseEnumCustomizer;
|
|
|
-import cc.uncarbon.framework.knife4j.customizer.Knife4jOpenApiCustomizerOverride;
|
|
|
|
|
|
|
+import cc.uncarbon.framework.knife4j.filter.AbstractSecurityFilter;
|
|
|
|
|
+import cc.uncarbon.framework.knife4j.filter.JakartaProductionSecurityFilter;
|
|
|
|
|
+import cc.uncarbon.framework.knife4j.filter.JakartaServletSecurityBasicAuthFilter;
|
|
|
|
|
+import cc.uncarbon.framework.knife4j.model.Knife4jHttpBasic;
|
|
|
|
|
+import cc.uncarbon.framework.knife4j.model.Knife4jProperties;
|
|
|
import cn.hutool.core.text.CharSequenceUtil;
|
|
import cn.hutool.core.text.CharSequenceUtil;
|
|
|
-import com.github.xiaoymin.knife4j.spring.configuration.Knife4jAutoConfiguration;
|
|
|
|
|
-import io.swagger.v3.oas.models.Components;
|
|
|
|
|
import io.swagger.v3.oas.models.OpenAPI;
|
|
import io.swagger.v3.oas.models.OpenAPI;
|
|
|
import io.swagger.v3.oas.models.info.Info;
|
|
import io.swagger.v3.oas.models.info.Info;
|
|
|
-import io.swagger.v3.oas.models.security.SecurityRequirement;
|
|
|
|
|
|
|
+import io.swagger.v3.oas.models.security.OAuthFlow;
|
|
|
|
|
+import io.swagger.v3.oas.models.security.OAuthFlows;
|
|
|
import io.swagger.v3.oas.models.security.SecurityScheme;
|
|
import io.swagger.v3.oas.models.security.SecurityScheme;
|
|
|
|
|
+import jakarta.servlet.DispatcherType;
|
|
|
|
|
+import lombok.NonNull;
|
|
|
import org.springdoc.core.configuration.SpringDocConfiguration;
|
|
import org.springdoc.core.configuration.SpringDocConfiguration;
|
|
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
|
|
|
|
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
|
|
|
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Bean;
|
|
|
import org.springframework.context.annotation.Import;
|
|
import org.springframework.context.annotation.Import;
|
|
|
import org.springframework.core.env.ConfigurableEnvironment;
|
|
import org.springframework.core.env.ConfigurableEnvironment;
|
|
@@ -21,13 +28,14 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Helio knife4j 自动配置类
|
|
* Helio knife4j 自动配置类
|
|
|
|
|
+ * @since 2.4.0 只保留 knife4j-ui,并从 knife4j 源码中移植「HTTP Basic鉴权机制」和「生产环境下不再显示开发文档」2个功能
|
|
|
*
|
|
*
|
|
|
* @author Uncarbon
|
|
* @author Uncarbon
|
|
|
* @author xiaoymin
|
|
* @author xiaoymin
|
|
|
*/
|
|
*/
|
|
|
-// 需要控制自动配置类加载顺序,去除显式 @EnableKnife4j
|
|
|
|
|
-@Import(value = {Knife4jOpenApiCustomizerOverride.class, HelioBaseEnumCustomizer.class, Knife4jAutoConfiguration.class, SpringDocConfiguration.class})
|
|
|
|
|
-@ConditionalOnExpression(value = "!${knife4j.production:false}")
|
|
|
|
|
|
|
+@Import(value = {HelioBaseEnumCustomizer.class, SpringDocConfiguration.class})
|
|
|
|
|
+@EnableConfigurationProperties({Knife4jProperties.class, Knife4jHttpBasic.class})
|
|
|
|
|
+@ConditionalOnExpression(value = "${knife4j.enable:false}")
|
|
|
@AutoConfiguration
|
|
@AutoConfiguration
|
|
|
public class HelioKnife4jAutoConfiguration {
|
|
public class HelioKnife4jAutoConfiguration {
|
|
|
|
|
|
|
@@ -40,24 +48,43 @@ public class HelioKnife4jAutoConfiguration {
|
|
|
|
|
|
|
|
// 全局安全要求
|
|
// 全局安全要求
|
|
|
String headerTokenName = CharSequenceUtil.blankToDefault(env.getProperty("sa-token.token-name"), "Authorization");
|
|
String headerTokenName = CharSequenceUtil.blankToDefault(env.getProperty("sa-token.token-name"), "Authorization");
|
|
|
- SecurityScheme securityScheme = new SecurityScheme()
|
|
|
|
|
- // 取个名字,方便被引用
|
|
|
|
|
- .name(headerTokenName)
|
|
|
|
|
- .type(SecurityScheme.Type.APIKEY)
|
|
|
|
|
- .in(SecurityScheme.In.HEADER);
|
|
|
|
|
|
|
+ openApi.schemaRequirement(headerTokenName, buildSecurityScheme());
|
|
|
|
|
+ return openApi;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- SecurityRequirement securityRequirement = new SecurityRequirement()
|
|
|
|
|
- // 引用上面定义的SecurityScheme
|
|
|
|
|
- .addList(headerTokenName);
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Security with Basic Http
|
|
|
|
|
+ * @param knife4jProperties Basic Properties
|
|
|
|
|
+ * @return BasicAuthFilter
|
|
|
|
|
+ */
|
|
|
|
|
+ @Bean
|
|
|
|
|
+ @ConditionalOnMissingBean(JakartaServletSecurityBasicAuthFilter.class)
|
|
|
|
|
+ @ConditionalOnExpression("${knife4j.basic.enable:false}")
|
|
|
|
|
+ public FilterRegistrationBean<JakartaServletSecurityBasicAuthFilter> securityBasicAuthFilter(@NonNull Knife4jProperties knife4jProperties) {
|
|
|
|
|
+ JakartaServletSecurityBasicAuthFilter authFilter = new JakartaServletSecurityBasicAuthFilter();
|
|
|
|
|
+ authFilter.setEnableBasicAuth(knife4jProperties.getBasic().isEnable());
|
|
|
|
|
+ authFilter.setUserName(knife4jProperties.getBasic().getUsername());
|
|
|
|
|
+ authFilter.setPassword(knife4jProperties.getBasic().getPassword());
|
|
|
|
|
+ authFilter.addRule(knife4jProperties.getBasic().getInclude());
|
|
|
|
|
|
|
|
- openApi
|
|
|
|
|
- .components(new Components()
|
|
|
|
|
- // 在components里定义SecurityScheme
|
|
|
|
|
- .addSecuritySchemes("APIKEY", securityScheme))
|
|
|
|
|
- // 添加SecurityRequirement作为全局安全要求
|
|
|
|
|
- .addSecurityItem(securityRequirement);
|
|
|
|
|
|
|
+ FilterRegistrationBean<JakartaServletSecurityBasicAuthFilter> registration = new FilterRegistrationBean<>();
|
|
|
|
|
+ registration.setDispatcherTypes(DispatcherType.REQUEST);
|
|
|
|
|
+ registration.setFilter(authFilter);
|
|
|
|
|
+ registration.setOrder(AbstractSecurityFilter.SPRING_FILTER_ORDER);
|
|
|
|
|
+ return registration;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return openApi;
|
|
|
|
|
|
|
+ @Bean
|
|
|
|
|
+ @ConditionalOnMissingBean(JakartaProductionSecurityFilter.class)
|
|
|
|
|
+ @ConditionalOnExpression("${knife4j.production:false}")
|
|
|
|
|
+ public FilterRegistrationBean<JakartaProductionSecurityFilter> productionSecurityFilter(@NonNull Knife4jProperties knife4jProperties) {
|
|
|
|
|
+ JakartaProductionSecurityFilter prodFilter = new JakartaProductionSecurityFilter(knife4jProperties.isProduction());
|
|
|
|
|
+
|
|
|
|
|
+ FilterRegistrationBean<JakartaProductionSecurityFilter> registration = new FilterRegistrationBean<>();
|
|
|
|
|
+ registration.setDispatcherTypes(DispatcherType.REQUEST);
|
|
|
|
|
+ registration.setFilter(prodFilter);
|
|
|
|
|
+ registration.setOrder(AbstractSecurityFilter.SPRING_FILTER_ORDER - 1);
|
|
|
|
|
+ return registration;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private Info buildInfo(HelioProperties helioProperties) {
|
|
private Info buildInfo(HelioProperties helioProperties) {
|
|
@@ -69,4 +96,18 @@ public class HelioKnife4jAutoConfiguration {
|
|
|
return info;
|
|
return info;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 利用OAuth2的安全规则,骗出 knife4j-ui 的请求头部输入框
|
|
|
|
|
+ */
|
|
|
|
|
+ private SecurityScheme buildSecurityScheme() {
|
|
|
|
|
+ OAuthFlow clientCredential = new OAuthFlow();
|
|
|
|
|
+ clientCredential.setTokenUrl("本页面无作用,只要请求接口时,在请求头带上Token即可");
|
|
|
|
|
+ OAuthFlows oauthFlows = new OAuthFlows();
|
|
|
|
|
+ oauthFlows.password(clientCredential);
|
|
|
|
|
+ SecurityScheme securityScheme = new SecurityScheme();
|
|
|
|
|
+ securityScheme.setType(SecurityScheme.Type.OAUTH2);
|
|
|
|
|
+ securityScheme.setFlows(oauthFlows);
|
|
|
|
|
+ return securityScheme;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|