如何有条件地跳过 Grails Spring 安全插件过滤器链中的 SecurityContextPersistenceFilter 过滤器

How to conditionally skip the SecurityContextPersistenceFilter filter in Grails Spring Security plugin filter chain

我有一个独特的场景,我试图在 Spring 安全插件(如果好奇的话,版本 1.2.7.3)的约束下解决。我创建了一个自定义 SSO 插件,允许使用签名 URL 登录。自定义插件效果很好,我根据文档添加了 resources.groovy 中的 bean 并添加到 BootStrap.groovy.

中的过滤器链中
SpringSecurityUtils.clientRegisterFilter('ssoFilter', SecurityFilterPosition.SECURITY_CONTEXT_FILTER.order + 10)

用户登录后一切正常,添加到安全上下文的现有活动会话对用户进行身份验证。

我有一个用例,其中一个已经通过身份验证的用户可能会在 SSO 请求上与另一个用户返回同一浏览器(即相同的会话 cookie)。我想让过滤器链注意到 URL.

的查询字符串中的 'sso=true'

我现在看到的行为是永远无法到达 SSO,因为原始用户已经通过安全上下文的身份验证。我无法在 SecurityContextPersistenceFilter 之前添加 SSO 过滤器,因为这会导致 SSO 过滤器不断被击中并且实际上没有呈现任何内容的问题。这遵循文档,其中我看到它说你不应该在安全上下文过滤器之前放置任何过滤器。

我曾研究过使用 'sso=true' 专门为 URL 创建一个特殊的过滤器链(我在未经身份验证的流程中通过添加自定义 RequestMatcher and AuthenticationEntryPoint implementation to the DelegatingAuthenticationEntryPoint 正在做的事情)通过使用springsecurity.filterChain.chainMap 配置说明。但是,从文档和实验来看,似乎只有路径被过滤了。

有没有办法确保无论何时在 URL 上看到 'sso=true',SSO 过滤器都会被命中,同时安全上下文仍然可用,或者 SecurityContextPersistenceFilter 可以通过请求 SSO 过滤器?

在我看来,您可以使用自定义 SecurityContextRepository

Version 1.2.7.3 of the Spring Security Grails plugin appears to use Spring Security 3.0.7. As mentioned in Section 8.3.1 of the Spring Security reference, from Spring Security 3.0 onward, the SecurityContextPersistenceFilter is configured with a SecurityContextRepository bean, which is responsible for loading and saving the SecurityContext. By default, this is an instance of HttpSessionSecurityContextRepository.

您可以创建一个扩展 HttpSessionSecurityContextRepository 的自定义 class。如果请求包含 sso=true 查询参数,自定义 subclass 可以覆盖 loadContext(HttpRequestResponseHolder) 方法以删除 "SPRING_SECURITY_CONTEXT" 会话属性。

您可以在 GitHub 的 Spring Security 3.0.7 中查看 HttpSessionSecurityContextRepository 的实现:
https://github.com/spring-projects/spring-security/blob/3.0.7.RELEASE/web/src/main/java/org/springframework/security/web/context/HttpSessionSecurityContextRepository.java

相关:How can I use Spring Security without sessions?

丹尼尔, 您的解决方案有效。 这是我的片段

@Override
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
    logger.debug("loadContext entry");
    String ssoParameter = requestResponseHolder.getRequest().getParameter("sso");

    if (ssoParameter != null && ssoParameter.equalsIgnoreCase("true")) {
        HttpSession session = requestResponseHolder.getRequest().getSession(false);
        if (session != null) session.invalidate();
    }
    return super.loadContext(requestResponseHolder);
}