2013-08-21 90 views
2

通常定义一些拦截的URL模式与春季安全配置对页面的访问自定义访问规则的Spring Security

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

我们现在有网址的那些事先不知道的页面。但是,我们可以编写一段代码来确定是否应该保护特定页面,也就是说,如果页面必须受到保护,我们可以提供返回true的服务。所以我们想要做的是这样的:

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

这怎么可以用Spring来实现?我们是否必须编写自定义过滤器?你将如何实现这样一个过滤器?

回答

2

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

春季安全配置:

<http use-expressions="true"> 
    <custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="accessFilter"/> 
    ... 
</http> 

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

筛选:

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 
    } 
} 
0

<intercept-url>标签所做的只是填充存储库(称为SecurityMetadataSource),其中RequestMatcher s被映射到ConfigAttribute s。 RequestMatcher s是根据pattern属性生成的,而ConfigAttribute仅保存access属性中指定的字符串。

当传入请求遇到FilterSecurityInterceptor筛选器时,它将迭代这些映射的列表以找到第一个条目,其中RequestMatcher表示匹配,以确定它必须执行哪种访问限制(描述由映射的ConfigAttribute)。

现在,如果你可以把你自己的RequestMatcher执行到这张地图上,你的需求基本上就可以解决了。困难在于名称空间配置不适合此用例,它只能将pattern属性解释为AntPathRequestMatcherRegexRequestMatcher

这意味着您必须在bean级别配置安全基础架构,因为<http>元素创建了自己的FilterSecurityInterceptor,这是无法替换的。

this article你可以找到如何编写这种手动安全配置的很大帮助。

+0

是否有可能在'FilterSecurityInterceptor'前会抛出一个'AccessDeniedException'添加自定义过滤器,如果当前用户是不允许访问该页面? – raymi

+1

当然,好的一点是,'ExceptionTranslationFilter'不关心''AccessDeniedException'被抛出的位置。它不必来自定制的'FilterSecurityInterceptor'。您也可以提供自己的过滤器,并且可能会更容易设置。 – zagyi