为什么我的Spring PreAuthFilter总是被调用?

时间:2012-09-27 13:19:39

标签: spring spring-mvc configuration spring-security

我的Spring 3.1应用程序配置如下

<http use-expressions="true" entry-point-ref="http401UnauthorizedEntryPoint">

    <intercept-url pattern="/app/demo" access="hasRole('Demo')" />
    <intercept-url pattern="/app/**" access="isAuthenticated()" />
    <intercept-url pattern="/admin/**" access="hasRole('Admin')" />

    <custom-filter position="PRE_AUTH_FILTER"
        ref="currentWindowsIdentityAuthenticationFilter" />

    <logout invalidate-session="true" delete-cookies="JSESSIONID"
        logout-url="/logout" logout-success-url="/logout-success" />

</http>

我编写了一个自定义preauth过滤器。当我在根网址/上调用我的应用时,过滤器链会挂钩并运行preauth过滤器,尽管此资源不受保护。这意味着注销不能按设计工作。注销后再次执行登录。

我的实施基于org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter类。

这是正常行为还是可以解决这个问题?我希望仅在受保护的URL上执行身份验证。

正如我所说,我不打算配置security='none',因为我想在所有页面上维护安全上下文。

我已在pastebin上发布了相应的注销信息。在这里包含它太冗长了。

2 个答案:

答案 0 :(得分:1)

似乎您想要的是创建特殊的<http>而没有任何用于注销网址的过滤器:

<http pattern="/logout/**" security="none" />

<http use-expressions="true" entry-point-ref="http401UnauthorizedEntryPoint">

    <intercept-url pattern="/app/demo" access="hasRole('Demo')" />
    <intercept-url pattern="/app/**" access="isAuthenticated()" />
    <intercept-url pattern="/admin/**" access="hasRole('Admin')" />

    <custom-filter position="PRE_AUTH_FILTER"
        ref="currentWindowsIdentityAuthenticationFilter" />

    <logout invalidate-session="true" delete-cookies="JSESSIONID"
        logout-url="/logout" logout-success-url="/logout-success" />

</http>

详细了解请求匹配机制here

修改

@LukeTaylor提到如果你想创建另一个过滤器链,那么模式应该放在元素中(这是明确记录的吗?),所以我的想法是单独的链而没有{{1}显然不会起作用。为PRE_AUTH_FILTER添加了<http>,没有任何过滤器,这可能会阻止在注销请求时进行授权。

但是,我不知道如何阻止像/logout这样的请求应用PRE_AUTH_FILTER。一种方法可能是放弃/other命名空间配置到manual filterChainProxy配置有两个<http>模式,但我不知道它是否值得。

@ Michael-O:关于异常<sec:filter-chain> - 这很奇怪,它是你的安全XML配置吗?或许这只是Luke所说的结果(另一个IllegalArgumentException: A universal match pattern ('/**') is defined before other patterns元素应该有模式)......

答案 1 :(得分:0)

我能够识别问题,但由于整个链的工作方式,它无法以现在的方式解决。

这是交易:

<http>上定义/**元素时,要求Spring Security在您定义的模式下的所有路径上触发整个过滤器链。无论其中一个是否需要保护都无关紧要。 Rob Winch发表了非常helpful video。如果您仔细查看default filter stack,那么您将应用哪些过滤器。在这些是我的过滤器。

我的日志文件的前十行显示,由于/<http>配置匹配,整个链都会被触发。最后,FilterSecurityInterceptor看到此资源不需要保护。更重要的是,您会看到CurrentWindowsIdentityAuthenticationFilter也被解雇并执行不需要的身份验证。

为什么呢?与基于标头的过滤器或URL处理过滤器相比,您没有触发/入口点来故意开始身份验证,无论URL是否需要保护,您都可以在不挑战客户端的情况下完成任务。定义类似<http pattern="/unprotected-url" security="none" />之类的东西可以保存您,因为您在不受保护的路径上丢失了安全上下文。无论URL保护如何,您都希望保持客户端登录。

现在如何解决这个问题?您有两种选择:

  1. <http>/app/**上定义一个/admin/**元素,但这真的很麻烦并且包含所有的重复。我不推荐这样的解决方案。此外,您可能不会在/**中的其他网址上使用sec上下文。这是不希望的。
  2. 在两个过滤器中拆分preauth过滤器:
    1. CurrentWindowsIdentityPreAuthenticationFilter
    2. CurrentWindowsIdentityUrlAuthenticationFilter
  3. 第二个选项解决了这个问题。

    CurrentWindowsIdentityPreAuthenticationFilter:保持原样并始终执行身份验证。对于脚本访问或REST请求等M2M通信非常有用。 CurrentWindowsIdentityUrlAuthenticationFilter:非常适合人与人之间的互动。它基本上像基于表单的过滤器。如果定义了一个URL,比如说/login,那么当您请求受保护的资源时,您将被重定向到您,并且在成功进行自动身份验证后,您将被重定向回您的实际资源。 Auth完成了。公共资源仍未经过身份验证,因为preauth过滤器仅在/login上触发,就像基于表单一样。如果您退出,则保持退出状态。

    如果春天的任何人都可以确认我的分析,我会很高兴。