package jnpf.config; import cn.dev33.satoken.annotation.handler.SaAnnotationHandlerInterface; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.interceptor.SaInterceptor; import cn.dev33.satoken.same.SaSameUtil; import cn.dev33.satoken.strategy.SaAnnotationStrategy; import cn.dev33.satoken.strategy.SaStrategy; import jnpf.annotation.SaCheckSame; import jnpf.base.UserInfo; import jnpf.consts.AuthConsts; import jnpf.filter.ClearThreadContextFilter; import jnpf.filter.RequestWrapperFilter; import jnpf.filter.SecurityFilter; import jnpf.handler.IRestHandler; import jnpf.encrypt.EncryptRestInterceptor; import jnpf.properties.SecurityProperties; import jnpf.util.StringUtil; import jnpf.util.UserProvider; import jnpf.util.context.SpringContext; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import jakarta.servlet.*; import java.lang.reflect.AnnotatedElement; import java.util.List; import java.util.function.BiFunction; /** * * @author JNPF开发平台组 * @copyright 引迈信息技术有限公司 */ @Slf4j @Configuration @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) public class SecurityConfiguration implements WebMvcConfigurer { @Autowired private SecurityProperties securityProperties; /** * 注册sa-token的拦截器 */ @Override public void addInterceptors(InterceptorRegistry registry) { initSaInterfaceAuth(registry); initEncryptRestInterceptor(registry); } /** * 请求封装过滤器 */ @Bean("myRequestWrapperFilter") @ConditionalOnMissingBean(name = "myRequestWrapperFilter") public Filter getRequestWrapperFilter(List handlers){ return new RequestWrapperFilter(handlers, securityProperties); } /** * 线程变量清除过滤器 */ @Bean("myClearThreadContextFilter") @ConditionalOnMissingBean(name = "myClearThreadContextFilter") public Filter getClearThreadContextFilter(){ return new ClearThreadContextFilter(); } /** * 来源验证、用户、租户设置过滤器 */ @Bean("mySecurityFilter") @ConditionalOnMissingBean(name = "mySecurityFilter") public Filter getSecurityFilter(SecurityProperties securityProperties, ConfigValueUtil configValueUtil){ return new SecurityFilter(securityProperties, configValueUtil).addInclude("/**"); } /** * 传输加密 */ @Bean("myEncryptRestInterceptor") @ConditionalOnMissingBean(name = "myEncryptRestInterceptor") @ConditionalOnProperty(prefix = "security", name = "enable-rest-encrypt", havingValue = "true") public HandlerInterceptor getEncryptRestInterceptor(){ return new EncryptRestInterceptor(); } protected void initEncryptRestInterceptor(InterceptorRegistry registry){ if(securityProperties.isEnableRestEncrypt()){ registry.addInterceptor(SpringContext.getBean("myEncryptRestInterceptor")); } } protected void initSaInterfaceAuth(InterceptorRegistry registry){ if(securityProperties.isEnablePreAuth()) { // 注册同源校验 SaAnnotationStrategy.instance.registerAnnotationHandler(new SaAnnotationHandlerInterface() { @Override public Class getHandlerAnnotationClass() { return SaCheckSame.class; } @Override public void checkMethod(SaCheckSame at, AnnotatedElement element) { SaSameUtil.checkToken(SaHolder.getRequest().getHeader(AuthConsts.INNER_TOKEN_KEY)); } }); // 开启接口请求权限控制 registry.addInterceptor(new SaInterceptor().isAnnotation(securityProperties.isEnablePreAuth())).addPathPatterns("/**"); } //接口鉴权忽略管理员、内部请求 BiFunction, String, Boolean> oldCheckFunc = SaStrategy.instance.hasElement; SaStrategy.instance.hasElement = (list, element) -> { //启用之后才验证 if (securityProperties.isEnablePreAuth()) { UserInfo userInfo = UserProvider.getUser(); //未获取到用户信息返回false if (StringUtil.isEmpty(userInfo.getUserId())) { return false; } //管理员返回true if (userInfo.getIsAdministrator()) { return true; } boolean result = oldCheckFunc.apply(list, element); //如果鉴权失败, 检测是否来自内部请求 if (!result) { String innerToken = SaHolder.getRequest().getHeader(AuthConsts.INNER_TOKEN_KEY); //来自内部请求(非网关) 无需鉴权 if (UserProvider.isValidInnerToken(innerToken)) { result = true; } } return result; } return true; }; } }