免责声明
正如 Spring Security FAQ 所提到的,您应该做的第一件事是问我真的应该这样做吗?安全性很复杂,应该对配置进行广泛的测试。允许配置动态更改只会使事情变得更加复杂,从而使应用程序更容易受到攻击。如果您真的想这样做,常见问题解答概述了完成此操作的基本方法。我已经扩展了下面的常见问题解答。
实现自定义 FilterInvocationSecurityMetadataSource
要动态获取安全 URL 映射,您可以实现自己的 FilterInvocationSecurityMetadataSource。下面给出一个示例实现。
注意:请记住,对于 Spring Security 拦截的每个请求都会调用 getAttributes,因此您很可能需要某种缓存。
public class JdbcFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
FilterInvocation fi = (FilterInvocation) object;
String url = fi.getRequestUrl();
HttpServletRequest request = fi.getHttpRequest();
// Instead of hard coding the roles lookup the roles from the database using the url and/or HttpServletRequest
// Do not forget to add caching of the lookup
String[] roles = new String[] { "ROLE_ADMIN", "ROLE_USER" };
return SecurityConfig.createList(roles);
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
创建一个 BeanPostProcessor
你不能使用命名空间来连接它,所以使用另一个 tip from the FAQ 你可以使用一个 BeanPostProcessor,它可能看起来像:
public class FilterInvocationSecurityMetadataSourcePostProcessor implements BeanPostProcessor, InitializingBean {
private FilterInvocationSecurityMetadataSource securityMetadataSource;
public Object postProcessAfterInitialization(Object bean, String name) {
if (bean instanceof FilterSecurityInterceptor) {
((FilterSecurityInterceptor)bean).setSecurityMetadataSource(securityMetadataSource);
}
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String name) {
return bean;
}
public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(securityMetadataSource,"securityMetadataSource cannot be null");
}
}
XML 配置
然后,假设上述两个 bean 都在包示例中,您将添加以下配置
<bean class="sample.FilterInvocationSecurityMetadataSourcePostProcessor">
<property name="securityMetadataSource">
<bean class="sample.JdbcFilterInvocationSecurityMetadataSource"/>
</property>
</bean>
可能的问题
如果您最终收到 ClassCastException,您可能会遇到 SEC-1957,该问题已在 Spring Security 3.1.1+ 中修复,请尝试更新到最新版本来解决此问题。