spring 安全过滤器应该直接调用身份验证提供程序吗?

Should spring security filters call authentication providers directly?

似乎有两种不同的模式:

模式 #1
GenericFilterBean 自己进行身份验证。大多数 out-of-the-box 过滤器使用:UsernamePasswordAuthenticationFilterDigestAuthenticationFilter 等。

  • 请求进入过滤器
  • 过滤器创建一个 Authenticationauthenticated=false
  • 过滤器将其传递给它直接引用的 specific AuthenticationProvider(有时通过 AuthenticationManager
  • 如果一切顺利,他们会创建一个 new 类型的 Authentication 并传回过滤器
  • 过滤器将其放入上下文中

    在此模式中,原始 Authentication 只不过是传递给 AuthenticationProvider 的 POJO - 它永远不会进入上下文。
    此外,通常情况下,过滤器还直接引用特定的 EntryPoint - 它在最后调用。
    (我认为这种模式适合 pre-authentication 过滤器?但是 Spring 代码中没有这种一致性)。

    模式 #2
    单独注册AuthenticationProviders做认证。正如大多数在线示例所使用的那样,但在 out-of-the-box 过滤器中很少见。

  • 请求进入过滤器
  • 过滤器创建一个 Authenticationauthenticated=false
  • filter 将其放入上下文中。
  • 过滤器的工作完成了
  • spring 安全性现在贯穿所有已注册 AuthenticationProviders
  • 其中一个选择了这个 Authentication 并尝试验证它
  • 如果一切顺利,他们会将 Authentication 突变为 authenticated=true

    在此模式中,过滤器不会直接调用 AuthenticationProviderEntryPoint。这些在外部注册并适用于所有过滤器。模式 #2 配置的典型示例:

    <sec:http use-expressions="true" entry-point-ref="myCustomEntryPoint" pattern="/**">
        <sec:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="myCustomFilter" />
        ...
    </sec:http>
    
    <sec:authentication-manager>
        <sec:authentication-provider ref="myCustomAuthenticationProvider" />
    </sec:authentication-manager>
    

    问题:何时使用一种方法或另一种方法是否有任何逻辑?

    模式 #2 感觉 最好。但我认为这两种方法都行得通,我不确定哪个是正确的/最好的/最安全的/最future-proof/最不可能与其他过滤器冲突的等等

    如果上下文很重要,这是 Spring 安全 3.2.5,并且将用于 token-based 身份验证,我们在其中验证令牌详细信息(取自请求 header)授予访问权限之前的远程服务。

  • 3年过去了,我觉得结论是没有对错之分!

    自从 Acegi 以来,Spring 安全性的核心并没有太大变化,它似乎是不同方法的混合体。

    最后,我选择了模式#1。我不喜欢模式 #2 使用的可变对象神奇地从 authenticated = false 变为 true!

    模式 #1 允许我使用两个不可变对象(一个始终验证为假,另一个始终验证为真 - 但仅在成功时添加),这实际上感觉更安全。