Spring Security的自定义访问规则

Custom Access Rules for Spring Security

通常,您定义一些拦截URL模式以配置对具有Spring安全性的页面的访问

1
2
3
4
<http use-expressions="true">
    <intercept-url pattern="/**/secure/**" access="hasRole('ROLE_SECURE_USER')" />
    ...
</http>

我们现在有一些带有url的页面,这些页面是事先未知的。但是我们可以编写一段代码来确定是否应保护特定页面,即,如果需要保护该页面,我们可以提供返回true的服务。所以我们要做的是这样的:

1
2
3
4
<http use-expressions="true">
    <intercept decide="@service.mustProtect()" access="hasRole('ROLE_SECURE_USER')" />
    ...
</http>

如何用Spring做到这一点?我们必须编写一个自定义过滤器吗?您将如何实现这样的过滤器?


实际上,通过在FilterSecurityInterceptor之前插入自定义过滤器很容易解决我们的问题。然后,您可以在过滤器的doFilter方法中抛出AccessDeniedException来触发身份验证。

Spring安全配置:

1
2
3
4
5
6
<http use-expressions="true">
    <custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="accessFilter"/>
    ...
</http>

<beans:bean id="accessFilter" class="xyz.AccessFilter" />

过滤器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class AccessFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (!currentUserCanAccessPage(request)) {
            throw new AccessDeniedException();
        }
        chain.doFilter(request,response)
    }

    private boolean currentUserCanAccessPage(ServletRequest request) {
        //implement
    }
}

<intercept-url>标记所做的只是填充一个存储库(称为SecurityMetadataSource),其中RequestMatcher被映射到ConfigAttributeRequestMatcher是基于pattern属性生成的,而ConfigAttribute只是保存在access属性中指定的字符串。

当传入请求命中FilterSecurityInterceptor过滤器时,它将遍历这些映射的列表以查找第一个条目(RequestMatcher表示匹配),以确定其必须具有哪种访问限制强制(由映射的ConfigAttribute描述)。

现在,如果您可以在地图上放置自己的RequestMatcher实现,则基本上可以解决您的要求。困难之处在于名称空间配置无法满足此用例,它只能将pattern属性解释为AntPathRequestMatcherRegexRequestMatcher

这意味着您将必须在Bean级别配置安全性基础结构,因为<http>元素会创建自己的不可替换的FilterSecurityInterceptor

在本文中,您可以找到有关如何编写这种手动安全配置的巨大帮助。