原文: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;
}
}