【问题标题】:Handling SAML Redirects on AJAX Requests处理 AJAX 请求上的 SAML 重定向
【发布时间】:2014-11-20 18:34:23
【问题描述】:

我有几个 AngularJS 应用程序都使用 Spring/Java 和 SAML 2.0 进行 SSO(利用 Spring Security SAML 扩展)。我的 SSO id 提供者是 OpenAM,一切运行良好。但是,当用户从一个应用程序中进行全局注销但打开其他选项卡时,我遇到了这种情况。由于这些是单页 Web 应用程序,许多功能可能仍然可以在孤立的选项卡中使用,直到用户执行某些操作来调用 ajax 请求。当然,这些 AJAX 请求会被 Spring Security SAML 过滤器拦截,并通过重定向到 OpenAM 登录 URL 触发身份验证尝试。当然,这会对浏览器造成严重破坏,因为 AJAX 请求不允许重定向到另一个域。此外,我无法对 Angular 的 $http 拦截器做任何事情,因为请求被“取消”并且 $http 错误回调函数中没有可用的质量信息(例如方便的 401/403 状态代码)。我只知道请求失败。

我不想假设所有错误的 $http 请求都是由于身份验证问题造成的(并执行 $window.location.reload()),因为失败可能有合理的原因。我的偏好是抑制 ajax 请求的 Spring Security 重定向(到 OpenAM 登录页面),而是发回 401/403 状态代码。这将允许我处理 $http 拦截器中的错误并在身份验证失败时执行整个页面加载,从而优雅地重定向到登录页面,就好像他们第一次访问该站点一样。

关于如何实现这一点的任何想法?

【问题讨论】:

    标签: angularjs spring-security saml-2.0 spring-saml


    【解决方案1】:

    负责初始化身份验证和决定返回 HTTP 错误、执行重定向、...的 bean 是 AuthenticationEntryPoint 的一个实例。要更改其行为,您可以:

    • 自定义当前SAMLEntryPoint(扩展commence方法)并覆盖默认行为,以防请求是来自Angular的AJAX调用,因此它返回HTTP错误而不是执行重定向到IDP
    • 或在您的 Spring 上下文中定义另一个 security:http 元素(在当前元素之前),它仅涵盖您的 AJAX 请求(例如,带有属性 pattern="/api/**")并使用以您想要的方式运行的入口点(参见 @987654326 @)

    【讨论】:

    • 弗拉基米尔...感谢您的回答。在您回复时,我发现了相同的解决方案。由于 Spring Security 是如此抽象,因此需要进行一些挖掘(而且我已经有一段时间没有深入研究它了),但我最终发现它是我需要扩展的 SAMLEntryPoint。现在我的角度 $http 拦截器可以在浏览器中适当地处理 403 响应。再次感谢!
    • 大家感谢您的指导,如果你们中的任何一个人能想出​​一个示例 github 教程,这对许多人来说将是非常有帮助的。干杯。
    • @HimalayMajumdar 和其他人请参阅我在博客上找到的解决方案,了解弗拉基米尔在他的第一个子弹中所说的内容
    【解决方案2】:

    提到弗拉基米尔的第一个子弹的可能实现 - 取自https://www.jasha.eu/blogposts/2015/10/saml-authentication-angularjs-spring-security.html

    public class XhrSamlEntryPoint extends SAMLEntryPoint {
    
      @Override
      public void commence(HttpServletRequest request, HttpServletResponse response,
                           AuthenticationException e) throws IOException, ServletException {
        if (isXmlHttpRequest(request) && e instanceof InsufficientAuthenticationException) {
          response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
          return;
        }
        super.commence(request, response, e);
      }
    
      private boolean isXmlHttpRequest(HttpServletRequest request) {
        return "XMLHttpRequest".equalsIgnoreCase(request.getHeader("X-Requested-With"));
      }
    }
    

    请记住,X-Requested-With 不是强制性标头,因此根据this answer,检测不是防弹的。就我而言,由于后端与 SPA 前端一起使用,因此我完全删除了对 ajax 调用的检查。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-23
      • 2019-03-08
      • 2018-06-13
      • 1970-01-01
      • 1970-01-01
      • 2014-05-19
      • 1970-01-01
      • 2015-09-27
      相关资源
      最近更新 更多