AngularJS $http,CORS和HTTP身份验证

87
因为在AngularJS中使用CORS和HTTP身份验证可能会有些棘手,所以我编辑了问题,分享了一个学到的教训。首先,我要感谢igorzg。他的答案帮了我很多。情境如下:您想使用AngularJS $http服务向不同的域发送POST请求。当使用AngularJS和服务器设置时,有几个需要注意的棘手问题。
第一点: 在应用程序配置中,必须允许跨域调用。
/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
app.config(function($httpProvider) {
    //Enable cross domain calls
    $httpProvider.defaults.useXDomain = true;
});

第二步: 您必须将withCredentials设置为true,并将用户名和密码放入请求中。
 /**
  *  Cors usage example. 
  *  @author Georgi Naumov
  *  gonaumov@gmail.com for contacts and 
  *  suggestions. 
  **/ 
   $http({
        url: 'url of remote service',
        method: "POST",
        data: JSON.stringify(requestData),
        withCredentials: true,
        headers: {
            'Authorization': 'Basic bashe64usename:password'
        }
    });

第三步:服务器设置。您必须提供:

/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Origin: http://url.com:8080");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");

对于每个请求。当你收到 OPTION 时,你必须传递:

/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
   header( "HTTP/1.1 200 OK" );
   exit();
}

HTTP身份验证及其后续内容。

以下是使用PHP的服务器端完整示例。

<?php
/**
 *  Cors usage example. 
 *  @author Georgi Naumov
 *  gonaumov@gmail.com for contacts and 
 *  suggestions. 
 **/ 
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Origin: http://url:8080");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Authorization");

if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
   header( "HTTP/1.1 200 OK" );
   exit();
}


$realm = 'Restricted area';

$password = 'somepassword';

$users = array('someusername' => $password);


if (isset($_SERVER['PHP_AUTH_USER']) == false ||  isset($_SERVER['PHP_AUTH_PW']) == false) {
    header('WWW-Authenticate: Basic realm="My Realm"');

    die('Not authorised');
}

if (isset($users[$_SERVER['PHP_AUTH_USER']]) && $users[$_SERVER['PHP_AUTH_USER']] == $password) 
{
    header( "HTTP/1.1 200 OK" );
    echo 'You are logged in!' ;
    exit();
}
?>

我的博客上有一篇关于这个问题的文章,可以在 这里 查看。


问题已经编辑过了。 - Georgi Naumov
2
我有点困惑,这是AngularJS,但你把它包在PHP标签中...我错过了什么吗? - onaclov2000
这只是服务器端逻辑的示例。下面的文本“第三步:服务器设置”是服务器端逻辑。 - Georgi Naumov
AngularJS是用于客户端的。它可以与任何服务器端进行通信,如PHP、Ruby、Perl、Python、Java、JavaScript等等...我还可以继续列举。 - Eric Hodonsky
1
这是一个问题吗?更像是一个好答案 :) - Mohammad Kermani
2个回答

43

不,你不必放置凭据,你需要在客户端放置标头,例如:

 $http({
        url: 'url of service',
        method: "POST",
        data: {test :  name },
        withCredentials: true,
        headers: {
                    'Content-Type': 'application/json; charset=utf-8'
        }
    });

而在服务器端,你需要为其设置头部信息。以下是Node.js的示例:

/**
 * On all requests add headers
 */
app.all('*', function(req, res,next) {


    /**
     * Response settings
     * @type {Object}
     */
    var responseSettings = {
        "AccessControlAllowOrigin": req.headers.origin,
        "AccessControlAllowHeaders": "Content-Type,X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5,  Date, X-Api-Version, X-File-Name",
        "AccessControlAllowMethods": "POST, GET, PUT, DELETE, OPTIONS",
        "AccessControlAllowCredentials": true
    };

    /**
     * Headers
     */
    res.header("Access-Control-Allow-Credentials", responseSettings.AccessControlAllowCredentials);
    res.header("Access-Control-Allow-Origin",  responseSettings.AccessControlAllowOrigin);
    res.header("Access-Control-Allow-Headers", (req.headers['access-control-request-headers']) ? req.headers['access-control-request-headers'] : "x-requested-with");
    res.header("Access-Control-Allow-Methods", (req.headers['access-control-request-method']) ? req.headers['access-control-request-method'] : responseSettings.AccessControlAllowMethods);

    if ('OPTIONS' == req.method) {
        res.send(200);
    }
    else {
        next();
    }


});

1
我怎么知道我需要什么? - Kevin Meredith
谢谢你的好回答 :) - Kamruzzaman
1
我感到困惑,如果端点由HTTP基本身份验证保护,为什么我不需要进行身份验证? - Maxim Zubarev
感谢您的回答。 - Naga Sandeep
当我尝试实现以上代码时,我遇到了以下错误:对预检请求的响应未通过访问控制检查:当请求的凭据模式为“包括”时,“Access-Control-Allow-Origin”标头的值不能是通配符“*”。因此,不允许访问来源为“http://localhost:3000”。XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。 - Kreena Mehta
显示剩余2条评论

3

要进行CORS请求,必须在请求中添加头信息,并且需要检查Apache是否启用了mode_header。

在Ubuntu中启用头信息的方法如下:

sudo a2enmod headers

为了让php服务器接受来自不同来源的请求,请使用:

Header set Access-Control-Allow-Origin *
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接