Spring Security 实现 antMatchers 配置路径的动态获取

时间:2025-04-11 14:26:28

原文:Spring Security 实现 antMatchers 配置路径的动态获取 - 黑帽子技术的个人空间 - OSCHINA - 中文开源技术交流社区​​​​​​

1,引入pom

<dependency>
    <groupId></groupId>
    <artifactId>hp-java-commons</artifactId>
    <version>1.1.3</version>
</dependency>

2,实现 SecurityConfigAttributeLoader (这里也可以从数据库获取)

@Configuration
@RefreshScope
public class MemorySecurityConfigAttributeLoader implements SecurityConfigAttributeLoader {

    @Value("${-list}")
    private String whiteList;

    @Value("${-list}")
    private String blackList;

    @Override
    public LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> loadConfigAttribute(HttpServletRequest request) {
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMatcherCollectionLinkedHashMap = new LinkedHashMap<>();
        if ((whiteList)) {
            ((",")).forEach(url -> {
                AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(url);
                SecurityAccessConfigHelper securityAccessConfigHelper = new SecurityAccessConfigHelper();
                List<ConfigAttribute> configAttributes = (().access());
                (antPathRequestMatcher, configAttributes);
            });
        }
        if ((blackList)) {
            ((",")).forEach(url -> {
                AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(url);
                SecurityAccessConfigHelper securityAccessConfigHelper = new SecurityAccessConfigHelper();
                List<ConfigAttribute> configAttributes = (().access());
                (antPathRequestMatcher, configAttributes);
            });
        }
        return requestMatcherCollectionLinkedHashMap;
    }
}

3,配置

  @Override
    public void configure(HttpSecurity http) throws Exception {     
               ().sessionCreationPolicy()
                .and().authorizeRequests()
                .anyRequest().authenticated()
                .withObjectPostProcessor(new CustomizeSecurityMetadataSourceObjectPostProcessor(new MemorySecurityConfigAttributeLoader()))
                .withObjectPostProcessor(new GlobalSecurityExpressionHandlerCacheObjectPostProcessor());
    }

4,扩展spring oauth2 资源服务器

package ;

import ;
import ;

public class ReflectUtils {
    public static Class<?>[] types(Object... values) {
        if (values == null) {
            return new Class[0];
        } else {
            Class<?>[] result = new Class[];

            for(int i = 0; i < ; ++i) {
                Object value = values[i];
                result[i] = value == null ?  : ();
            }

            return result;
        }
    }
    private static class NULL {
        private NULL() {
        }
    }
    public static Method similarMethod(Class t, String name, Class<?>[] types) throws NoSuchMethodException {
        Method[] var4 = ();
        int var5 = ;

        int var6;
        Method method;
        for(var6 = 0; var6 < var5; ++var6) {
            method = var4[var6];
            if ((method, name, types)) {
                return method;
            }
        }

        do {
            var4 = ();
            var5 = ;

            for(var6 = 0; var6 < var5; ++var6) {
                method = var4[var6];
                if (isSimilarSignature(method, name, types)) {
                    return method;
                }
            }

            t = ();
        } while(t != null);

        throw new NoSuchMethodException("No similar method " + name + " with params " + (types) + " could be found on type .");
//        throw new NoSuchMethodException("No similar method " + name + " with params " + (types) + " could be found on type " + () + ".");
    }
    private static boolean isSimilarSignature(Method possiblyMatchingMethod, String desiredMethodName, Class<?>[] desiredParamTypes) {
        return ().equals(desiredMethodName) && match((), desiredParamTypes);
    }
    private static boolean match(Class<?>[] declaredTypes, Class<?>[] actualTypes) {
        if ( == ) {
            for(int i = 0; i < ; ++i) {
                if (actualTypes[i] !=  && !wrapper(declaredTypes[i]).isAssignableFrom(wrapper(actualTypes[i]))) {
                    return false;
                }
            }

            return true;
        } else {
            return false;
        }
    }
    public static <T> Class<T> wrapper(Class<T> type) {
        if (type == null) {
            return null;
        } else {
            if (()) {
                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }

                if ( == type) {
                    return (Class<T>) ;
                }
            }

            return type;
        }
    }
    public static Method exactMethod(Class t,String name, Class<?>[] types) throws NoSuchMethodException {
        try {
            return (name, types);
        } catch (NoSuchMethodException var7) {
            while(true) {
                try {
                    return (name, types);
                } catch (NoSuchMethodException var6) {
                    t = ();
                    if (t == null) {
                        throw new NoSuchMethodException();
                    }
                }
            }
        }
    }
}
package ;

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import .*;

/**
 * @author lwc
 */
public class CustomizeConfigSourceFilterInvocationSecurityMetadataSource extends DefaultFilterInvocationSecurityMetadataSource {


    private SecurityMetadataSource delegate;
    private SecurityConfigAttributeLoader metadataSourceLoader;
    private ExpressionParser expressionParser;
    private SecurityExpressionHandler<FilterInvocation> expressionHandler;

    public CustomizeConfigSourceFilterInvocationSecurityMetadataSource(
            SecurityMetadataSource delegate,
            SecurityConfigAttributeLoader metadataSourceLoader, SecurityExpressionHandler<FilterInvocation> expressionHandler) {
        super(new LinkedHashMap<>());
         = delegate;
         = metadataSourceLoader;
         = expressionHandler;

        copyDelegateRequestMap();
    }

    private void copyDelegateRequestMap() {
        (this,"requestMap",getDelegateRequestMap());
    }

    private LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> getDelegateRequestMap() {
        return (LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>) (,"requestMap");
    }


    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) {
        final HttpServletRequest request = ((FilterInvocation) object).getRequest();
        Collection<ConfigAttribute> configAttributes = new ArrayList<>();
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap =
                (request);

        if (requestMap == null || () == 0) {
            ((object));
            return configAttributes;
        }

        if (()) {
             = ();
        }


        Class<ExpressionBasedFilterInvocationSecurityMetadataSource> expressionBasedFilterInvocationSecurityMetadataSourceClass = ;//ExpressionBasedFilterInvocationSecurityMetadataSource
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> webExpressionRequestMap = null;
        Class<?>[] types = (requestMap, );
        try {
            Method processMap = (expressionBasedFilterInvocationSecurityMetadataSourceClass, "processMap", types);
            (true);
            webExpressionRequestMap = (LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>) (expressionBasedFilterInvocationSecurityMetadataSourceClass, requestMap, );

        } catch (Exception e) {
            try {
                Method processMap = (expressionBasedFilterInvocationSecurityMetadataSourceClass, "processMap", types);
                (true);
                webExpressionRequestMap = (LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>) (expressionBasedFilterInvocationSecurityMetadataSourceClass, requestMap, );
            } catch (Exception noSuchMethodException) {
                ();
            }
        }

        for (<RequestMatcher, Collection<ConfigAttribute>> entry : ()) {
            if (().matches(request)) {
                (());
                break;
            }
        }

        ((object));
        return configAttributes;
    }
}
package ;

import ;
import ;
import ;
import ;

/**
 * @author lwc
 */
public class CustomizeSecurityMetadataSourceObjectPostProcessor implements ObjectPostProcessor<FilterSecurityInterceptor> {

    private SecurityConfigAttributeLoader securityConfigAttributeLoader;

    private SecurityExpressionHandler<FilterInvocation> expressionHandler;

    public CustomizeSecurityMetadataSourceObjectPostProcessor(SecurityConfigAttributeLoader securityConfigAttributeLoader, SecurityExpressionHandler<FilterInvocation> expressionHandler) {
         = securityConfigAttributeLoader;
         = expressionHandler;
    }

    @Override
    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
        FilterSecurityInterceptor interceptor = object;

        CustomizeConfigSourceFilterInvocationSecurityMetadataSource metadataSource =
                new CustomizeConfigSourceFilterInvocationSecurityMetadataSource(
                        (), securityConfigAttributeLoader, expressionHandler);
        (metadataSource);
        return (O) interceptor;
    }
}
package ;

import ;
import ;

/**
 * @author lwc
 */
public class SecurityAccessConfigHelper {

    public static final String PERMIT_ALL = "permitAll";
    public static final String DENY_ALL = "denyAll";
    public static final String ANONYMOUS = "anonymous";
    public static final String AUTHENTICATED = "authenticated";
    public static final String FULLY_AUTHENTICATED = "fullyAuthenticated";
    public static final String REMEMBER_ME = "rememberMe";

    private StringBuilder access = new StringBuilder();

    public SecurityAccessConfigHelper permitAll() {
        and();
        (PERMIT_ALL);
        return this;
    }

    public SecurityAccessConfigHelper denyAll() {
        and();
        (DENY_ALL);
        return this;
    }

    public SecurityAccessConfigHelper anonymous() {
        and();
        (ANONYMOUS);
        return this;
    }

    public SecurityAccessConfigHelper authenticated() {
        and();
        (AUTHENTICATED);
        return this;
    }

    public SecurityAccessConfigHelper fullyAuthenticated() {
        and();
        (FULLY_AUTHENTICATED);
        return this;
    }

    public SecurityAccessConfigHelper rememberMe() {
        and();
        (REMEMBER_ME);
        return this;
    }

    public SecurityAccessConfigHelper hasAnyRole(String... authorities) {
        String anyAuthorities = (authorities,
                "','ROLE_");
        and();
        ("hasAnyRole('ROLE_" + anyAuthorities + "')");
        return this;
    }

    public SecurityAccessConfigHelper hasRole(String role) {
        (role, "role cannot be null");
        if (("ROLE_")) {
            throw new IllegalArgumentException(
                    "role should not start with 'ROLE_' since it is automatically inserted. Got '"
                            + role + "'");
        }

        and();
        ("hasRole('ROLE_" + role + "')");
        return this;
    }

    public SecurityAccessConfigHelper hasAnyAuthority(String... authorities) {
        String anyAuthorities = (authorities, "','");
        and();
        ("hasAnyAuthority('" + anyAuthorities + "')");
        return this;
    }

    public SecurityAccessConfigHelper hasAuthority(String authority) {
        and();
        ("hasAuthority('" + authority + "')");
        return this;
    }

    public SecurityAccessConfigHelper hasIpAddress(String ipAddressExpression) {
        and();
        ("hasIpAddress('" + ipAddressExpression + "')");
        return this;
    }

    public String access() {
        return ();
    }


    private SecurityAccessConfigHelper and() {
        if (() != 0) {
            (" and ");
        }
        return this;
    }
}
package ;

import ;
import ;

import ;
import ;
import ;

/**
 * @author lwc
 */
public interface SecurityConfigAttributeLoader {

    LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> loadConfigAttribute(HttpServletRequest request);
}
package ;

import ;
import ;
import ;
import ;
import .slf4j.Slf4j;
import .;
import ;
import ;
import ;
import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;
import ;

/**
 * @author liwenchao
 */
@Configuration
@RefreshScope
@Slf4j
public class MemorySecurityConfigAttributeLoader implements SecurityConfigAttributeLoader {

    @Override
    public LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> loadConfigAttribute(HttpServletRequest request) {
        LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMatcherCollectionLinkedHashMap = new LinkedHashMap<>();
        //获取当前环境
        String activeProfile = ();
        String application = ("application");
        ("crm当前运行环境:{}",activeProfile);
        ("crm请求头application:{}",application);
        if (!"app".equalsIgnoreCase(application) || "local".equalsIgnoreCase(activeProfile)) {
            AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher("/**");
            SecurityAccessConfigHelper securityAccessConfigHelper = new SecurityAccessConfigHelper();
            List<ConfigAttribute> configAttributes = (().access());
            (antPathRequestMatcher,configAttributes);
            return requestMatcherCollectionLinkedHashMap;
        }
        JSONObject whiteAndBlackList = ();
        String white = ("white");
        String black = ("black");
        ("crm黑白名单列表:{}",whiteAndBlackList);
        if ((white)) {
            ((",")).forEach(url -> {
                AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(url);
                SecurityAccessConfigHelper securityAccessConfigHelper = new SecurityAccessConfigHelper();
                List<ConfigAttribute> configAttributes = (().access());
                (antPathRequestMatcher, configAttributes);
            });
        }
        if ((black)) {
            ((",")).forEach(url -> {
                AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(url);
                SecurityAccessConfigHelper securityAccessConfigHelper = new SecurityAccessConfigHelper();
                List<ConfigAttribute> configAttributes = (().access());
                (antPathRequestMatcher, configAttributes);
            });
        }
        return requestMatcherCollectionLinkedHashMap;
    }
}
package ;

import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .;
import .;
import .;
import ..OAuth2AuthenticationManager;
import ..OAuth2WebSecurityExpressionHandler;
import .;
import .;
import .;
import .;
import ;
import ;

/**
 * @Description
 * @Author lwc
 * @Data 2022/8/29 22:26
 */
@Configuration
@EnableResourceServer //开启资源服务器功能
@EnableWebSecurity(debug = true)  //开启web访问安全
@RefreshScope
@Slf4j
public class ResourceServerConfiger extends ResourceServerConfigurerAdapter {

    @Value("${-key}")
    private String SIGN_KEY; //jwt签名密钥
    //    private String sign_key = "imugua20220829"; //jwt签名密钥 ee7dcc6cad12f7d7ef9642e680fdbc4d
    @Value("${}")
    private String release; //资源服务器标识

    private SecurityExpressionHandler<FilterInvocation> expressionHandler = new OAuth2WebSecurityExpressionHandler();

    /**
     * @Description 该⽅法⽤于定义资源服务器向远程认证服务器发起请求,进⾏token校验
     * 等事宜
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        /*// 设置当前资源服务的资源id
        ("release");
        // 定义token服务对象(token校验就应该靠token服务对象)
        RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
        // 校验端点/接⼝设置
        ("http://localhost:9999/oauth/check_token");
        // 携带客户端id和客户端安全码
        ("clientmugua");
        ("zbcxyz");

        (remoteTokenServices);*/

        //使用jwt令牌
        (release).tokenStore(tokenStore()).stateless(true);//无状态设置
    }

    /**
     * @Description 场景:⼀个服务中可能有很多资源(API接⼝)
     * * 某⼀些API接⼝,需要先认证,才能访问
     * * 某⼀些API接⼝,压根就不需要认证,本来就是对外开放的接⼝
     * * 我们就需要对不同特点的接⼝区分对待(在当前configure⽅法中
     * 完成),设置是否需要经过认证
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {


        ().sessionCreationPolicy()
                .and().authorizeRequests()
                .expressionHandler(expressionHandler)
                .anyRequest().authenticated()
                .withObjectPostProcessor(new CustomizeSecurityMetadataSourceObjectPostProcessor(new MemorySecurityConfigAttributeLoader(), expressionHandler));
    }

    /**
     * @Description 该⽅法⽤于创建tokenStore对象(令牌存储对象)
     * token以什么形式存储
     */
    public TokenStore tokenStore() {
        //return new InMemoryTokenStore();
        // 使⽤jwt令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }


    /**
     * @Description * 返回jwt令牌转换器(帮助我们⽣成jwt令牌的)
     * 在这⾥,我们可以把签名密钥传递进去给转换器对象
     */
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        (SIGN_KEY); // 签名密钥
        (new MacSigner(SIGN_KEY)); // 验证时使⽤的密钥,
        // 和签名密钥保持⼀致3.3.5 从数据库加载Oauth2客户端信息
        // 创建数据表并初始化数据(表名及字段保持固定)
        return jwtAccessTokenConverter;
    }
}