【问题标题】:CAS authentication and redirects with jQuery AJAX使用 jQuery AJAX 进行 CAS 身份验证和重定向
【发布时间】:2014-02-12 17:53:37
【问题描述】:

我有一个 HTML 页面,它需要使用 jQuery AJAX 函数向受 CAS 保护的 (Central Authentication Service) Web 服务发出请求。我有以下代码:

$.ajax({
    type: "GET",
    url: request,
    dataType: "json",
    complete: function(xmlHttp) {
        console.log(xmlHttp);
        alert(xmlHttp.status);
    },
    success: handleRedirects
});

request 变量可以指向 CAS 服务器 (https://cas.mydomain.com/login?service=myServiceURL) 或直接指向服务(然后应重定向回 CAS 以获取服务票证)。 Firebug 显示该请求正在发出并且它以 302 重定向返回。但是,$.ajax() 函数不处理重定向。

我写了这个函数来解决这个问题:

var handleRedirects = function(data, textStatus) {
    console.log(data, textStatus);
    if (data.redirect) {
       console.log("Calling a redirect: " + data.redirect);
       $.get(data.redirect, handleRedirects);
    } else {
        //function that handles the actual data processing
        gotResponse(data);
    }
};

但是,即使这样,handleRedirects 函数也不会被调用,xmlHttp.status 总是返回 0。它看起来也不像 cas.mydomain.com 调用发送的 cookie。 (有关类似问题,请参阅this question。)

这是 AJAX 调用不处理重定向的问题,还是这里发生的事情比想象的要多?

【问题讨论】:

    标签: authentication redirect jquery


    【解决方案1】:

    确实发生的事情比表面上看到的要多。

    经过一番调查,如果以这种方式发出的 jQuery AJAX 请求不是针对同一个子域发出的,它们似乎会失败。在此示例中,正在从不同的服务器向 cas.mydomain.com 发出请求。即使它也在mydomain.com,请求也会失败,因为子域不匹配

    jQuery AJAX 可以正确处理重定向。我在同一个子域上使用脚本进行了一些测试以验证这一点。此外,cookie 也会按您的预期传递。有关这项研究,请参阅 my blog post

    还请记住,协议必须相同。也就是说,由于cas.mydomain.com 使用的是 HTTPS,因此您从中调用它的页面也必须使用 HTTPS,否则请求将失败。

    【讨论】:

    • 你有没有找到解决这个问题的方法?我读了你的博客文章,建议使用 JSONP,这是我在其他地方读到的。但是,看起来 CORS 是解决此问题的方法,但我仍然无法让 302 重定向正常工作。
    【解决方案2】:

    浏览器不允许跨域调用。最简单的方法是在移动应用端使用 JSONP,并使用 CAS 网关返回票证。

    【讨论】:

      【解决方案3】:

      您可以使用 PHP 代理进行此类跨域 AJAX 调用。在以下示例中,代理能够调用返回 JSON 字符串的 REST Web 服务。

      wsproxy.php

      <?php
      
      if (!isset($_POST["username"]) || !isset($_POST["password"]))
          die("Username or password not set.");
      
      $username = $_POST["username"];
      $password = $_POST["password"];
      
      if (!isset($_GET['url'])
          die("URL was not set.");
      
      //Rebuild URL (needed if the url passed as GET parameter
      //also contains GET parameters
      $url = $_GET['url'];
      foreach ($_GET as $key => $value) { 
          if ($key != 'url') {
              $url .= "&" . $key . "=" . $value;
          }
      }
      
      //Set username and password for HTTP Basic Authentication
      $context = stream_context_create(array(
          'http' => array(
          'header'  => "Authorization: Basic " . base64_encode("$username:$password")
          )
      ));
      
      //Call WS
      $json = file_get_contents($url, false, $context);
      
      // Read HTTP Status
      if(isset($http_response_header[0]))
          list($version,$status_code,$msg) =
              explode(' ',$http_response_header[0], 3);
      
      // Check HTTP Status
      if($status_code != 200) {
          if($status_code == 404) {
              die("404 - Not Found");
          } else {
              die($status_code . " - Error");
          }
      }
      
      //Add content header
      header('Content-Type: application/json');
      print $json;
      
      ?>
      

      网址使用

      http://yourDomain.com/wsproxy.php?url=https://wsToCall.com/ws/resource?param1=false&param2=true

      jQuery $.ajax$.post

      请注意,如果您不需要传递用户名和密码,则 GET 请求就足够了。

      $.ajax({
          type : "POST",
          url : "http://" + document.domain +
              "/wsproxy.php?url=http://wsToCall.com/ws/resource?param1=false&param2=true",
          dataType : "json",
          success : handleRedirects,
          data: { username: "foo", password: "bar" }
      });
      

      【讨论】:

      • 您可能遇到的一个问题是代理不会使用用户的会话信息。在我的情况下,我试图通过向 CAS 服务器发送服务器端请求来将用户登录到 CAS 服务 - 我得到的服务票证确实在服务上对他们进行了身份验证,但他们没有登录到服务器本身(丢失了一些一开始就设置 SSO 的好处)。
      猜你喜欢
      • 2012-04-30
      • 2011-07-27
      • 2021-11-27
      • 1970-01-01
      • 2017-02-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多