springsecuriy4官方案例中的URL拦截规则在容器初始化时加载完成,后面如果URL拦截规则需求有变化,则只有修改配置,重启容器。
通过自定义FilterInvocationSecurityMetadataSource实现类 ProtectedUrlSecurityMetadataSource就可以完成URL拦截规则运行时重新加载。
FilterSecurityInterceptor有一个小bug,所以ProtectedUrlSecurityMetadataSource必须使用配套的FilterSecurityInterceptor子类ProtectedUrlFilter 来进行URL权限验证。bug描述见 https://github.com/spring-projects/spring-security/pull/4997
ProtectedUrlSecurityMetadataSource核心代码见:
/** * @param urlMap 存储URL和权限的对应关系 */ public synchronized void loadSecurityMetadataSourceFromUrlMap(Map<String, String> urlMap) { LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap(urlMap.size()); for (Map.Entry<String, String> entry : urlMap .entrySet()) { RequestMatcher requestMatcher = new AntPathRequestMatcher(entry.getKey()); Set<String> set = StringUtils.commaDelimitedListToSet(entry.getValue()); Collection<ConfigAttribute> configAttributes = new LinkedHashSet<>(set.size()); for (String str : set) { configAttributes.add(new SecurityConfig(str)); } requestMap.put(requestMatcher, configAttributes); } FilterInvocationSecurityMetadataSource metadataSource = new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, new DefaultWebSecurityExpressionHandler()); this.securityMetadataSource = metadataSource; }
具体的配置案例见:SpringSecurityConfig.buildProtectedUrlFilter;
如何从数据库中加载URL配置规则?
1.在自己的controller中注入ProtectedUrlSecurityMetadataSource,
2.从数据库中获得所有URL的拦截规则,然后赋值到Map,
3.调用loadSecurityMetadataSourceFromUrlMap方法,完成拦截规则的重新加载。
@Autowired ProtectedUrlSecurityMetadataSource metadataSource; @GetMapping("/access/clear") public String clear() { metadataSource.loadSecurityMetadataSourceFromUrlMap(new HashMap<>()); return "/home"; }ProtectedUrlSecurityMetadataSource 拦截规则可以使用web security expressions,保留springsecurity4本身的优势部分,同时提供外部接口,可以运行时重新加载拦截规则,提高了灵活性。
强大的WSE :https://springcloud.cc/spring-security-zhcn.html#el-access-web
源码地址:https://gitee.com/json20080301/spring-boot-spring-security-thymeleaf