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

Posted

技术标签:

【中文标题】如何有条件地跳过 Grails Spring Security 插件过滤器链中的 SecurityContextPersistenceFilter 过滤器【英文标题】:How to conditionally skip the SecurityContextPersistenceFilter filter in Grails Spring Security plugin filter chain 【发布时间】:2015-07-20 17:04:39 【问题描述】:

我有一个独特的场景,我试图在 Spring Security 插件(如果好奇,版本 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”(我在未经身份验证的流程中通过将自定义RequestMatcher 和AuthenticationEntryPoint 实现添加到DelegatingAuthenticationEntryPoint)专门为URL 创建一个特殊的过滤器链)使用springsecurity.filterChain.chainMap 配置说。但是,从文档和实验看来,只有路径被过滤了。

有没有办法确保每当在 URL 上看到“sso=true”时,SSO 过滤器就会被命中,同时仍然可以访问安全上下文,或者 SecurityContextPersistenceFilter 可以将请求传递给 SSO 过滤器?

【问题讨论】:

【参考方案1】:

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

Version 1.2.7.3 Spring Security Grails 插件似乎使用 Spring Security 3.0.7。正如Section 8.3.1 of the Spring Security reference 中提到的,从Spring Security 3.0 开始,SecurityContextPersistenceFilter 配置了一个SecurityContextRepository bean,它负责加载和保存SecurityContext。默认情况下,这是HttpSessionSecurityContextRepository 的一个实例。

您可以创建一个扩展 HttpSessionSecurityContextRepository 的自定义类。如果请求包含sso=true 查询参数,自定义子类可以覆盖 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?

【讨论】:

【参考方案2】:

丹尼尔, 你的解决方案奏效了。 这是我的sn-p

@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);

【讨论】:

以上是关于如何有条件地跳过 Grails Spring Security 插件过滤器链中的 SecurityContextPersistenceFilter 过滤器的主要内容,如果未能解决你的问题,请参考以下文章

如何有条件地跳过python中for循环中的迭代步骤数?

有条件地跳过案例

我可以有条件地跳过在同一个文件中加载“更多”红宝石代码吗?

运行测试时如何优雅地跳过 express-jwt 中间件?

rails .each 无缘无故地跳过第二个元素

运行 GRAILS run-app 时如何跳过插件更新提示?