springsecurity如何动态配置url权限呢?如果还需要自己手动配置就太那个了,下面来看看动态是如何实现的。
在spring security中,有着各种内置的filter,这里我们来重写一下SecurityMetadataSource用以动态获取url权限配置,再用AccessDecisionManager进行权限判断。
MyAccessDecisionManager
public class MyAccessDecisionManager implements org.springframework.security.access.AccessDecisionManager { @Override public void decide(Authentication authentication, Object object , Collection < ConfigAttribute > configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if (CollectionUtils.isEmpty(configAttributes)) { throw new AccessDeniedException("not allow"); } Iterator < ConfigAttribute > ite = configAttributes.iterator(); while (ite.hasNext()) { ConfigAttribute ca = ite.next(); String needRole = ((org.springframework.security.access.SecurityConfig) ca) .getAttribute(); for (GrantedAuthority ga: authentication.getAuthorities()) { if (ga.getAuthority() .equals(needRole)) { //匹配到有对应角色,则允许通过 return; } } } //该url有配置权限,但是当然登录用户没有匹配到对应权限,则禁止访问 throw new AccessDeniedException("not allow"); } @Override public boolean supports(ConfigAttribute attribute) { return true; } @Override public boolean supports(Class < ? > clazz) { return true; } }
上面我们看到会遍历判断出这个url所需的角色看用户是否具备,具备就返回,否则就抛出AccessDeniedException异常
MyFilterInvocationSecurityMetadataSource
public class MyFilterInvocationSecurityMetadataSource implements org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource { private final AntPathMatcher antPathMatcher = new AntPathMatcher(); private final Map < String, String > urlRoleMap = new HashMap < String, String > () { { put("/open/**", "ROLE_ANONYMOUS"); put("/health", "ROLE_ANONYMOUS"); put("/restart", "ROLE_ADMIN"); put("/demo", "ROLE_USER"); } }; @Override public Collection < ConfigAttribute > getAttributes(Object object) throws IllegalArgumentException { FilterInvocation fi = (FilterInvocation) object; String url = fi.getRequestUrl(); // String httpMethod = fi.getRequest().getMethod(); for (Map.Entry < String, String > entry: urlRoleMap.entrySet()) { if (antPathMatcher.match(entry.getKey(), url)) { return SecurityConfig.createList(entry.getValue()); } } //没有匹配到,默认是要登录才能访问 return SecurityConfig.createList("ROLE_USER"); // return null; } @Override public Collection < ConfigAttribute > getAllConfigAttributes() { return null; } @Override public boolean supports(Class < ? > clazz) { return FilterInvocation.class.isAssignableFrom(clazz); } }
这里我们以内存的map来show一下,实际应用是可以从分布式配置中心或数据库中读取的。
SecurityConfig
再来综合配置下,如:
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest() .authenticated() .withObjectPostProcessor(new ObjectPostProcessor < FilterSecurityInterceptor > () { public < O extends FilterSecurityInterceptor > O postProcess( O fsi) { fsi.setSecurityMetadataSource(mySecurityMetadataSource()); fsi.setAccessDecisionManager(myAccessDecisionManager()); return fsi; } }); } @Bean public FilterInvocationSecurityMetadataSource mySecurityMetadataSource() { MyFilterInvocationSecurityMetadataSource securityMetadataSource = new MyFilterInvocationSecurityMetadataSource(); return securityMetadataSource; } @Bean public AccessDecisionManager myAccessDecisionManager() { return new MyAccessDecisionManager(); } }
以上就是本篇文章的所有内容,对java架构师还有不懂得的知识的话,可以来我们网站查询答案。
推荐阅读: