CORS AngularJS 不使用 POST 或 DELETE 发送 Cookie/凭据,但 GET OK

Posted

技术标签:

【中文标题】CORS AngularJS 不使用 POST 或 DELETE 发送 Cookie/凭据,但 GET OK【英文标题】:CORS AngularJS Not Sending Cookie/Credentials with POST or DELETE but GET OK 【发布时间】:2013-12-24 00:47:56 【问题描述】:

我有一个 ExpressJS API 服务器和一个 ExpressJS w/AngularJS 应用程序在本地开发中运行。

CORS GET 请求工作正常,但 POST 和 DELETE 未发送任何 cookie(凭据)。

我尝试了各种配置选项,但该应用从未发送过 POST 或 DELETE 凭据。

我希望有人熟悉这一点并且可能会看到我哪里出错了。

我在 /etc/hosts 中设置了两个本地域:

127.0.0.1 rsm.local
127.0.0.1 api.rsm.local

所以http://rsm.local 正在向http://api.rsm.local 发送api 请求

AngularJS 正在使用 Restangular。

会话存储在 MongoDB 中,域为 .rsm.local,因此两个服务器都可以读取 cookie。

客户端应用程序和 api 服务器使用相同的 cookie 密钥和秘密。

app.use(express.session(
key: config.cookie_key,
secret: config.cookie_secret,
cookie: 
    domain:'.rsm.local',
    expires: config.cookie_expire
,
store: new mongoStore(
    url: config.database,
    collection: 'sessions',
    auto_reconnect: true
)
));

这似乎工作正常,会话状态在两个应用程序之间共享正常。

API 服务器是用标准设置的,我认为是正确的 CORS 标头:

app.all('/api/*', function(req, res, next) 
res.setHeader('Access-Control-Allow-Origin', 'http://rsm.local:3000');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,DELETE,OPTIONS');
res.setHeader("Access-Control-Allow-Headers", "Accept, Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
res.setHeader('Access-Control-Allow-Credentials', true);
next();
);

我相信客户端应用 AngularJS 已将 Restanguarl 配置为正确发送凭据:

angular.module('rsm').config(function (RestangularProvider) 

RestangularProvider.setBaseUrl('http://api.rsm.local:3001/api/v1');

RestangularProvider.setDefaultHttpFields(
withCredentials: true,
useXDomain : true
);

);

所以 GET 请求一切正常(例如列出所有并列出一个):

这是一个 GET 请求的示例(没有飞行前请求),我们可以看到 cookie 是跨域发送的,并且响应作为 CORS 全部正确排列:

Request URL:http://api.rsm.local:3001/api/v1/articles
Request Method:GET
Status Code:200 OK

Request Headers
GET /api/v1/articles HTTP/1.1
Host: api.rsm.local:3001
Connection: keep-alive
Accept: application/json, text/plain, */*
Origin: http://rsm.local:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Referer: http://rsm.local:3000/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: rsm.sid=s%3A84buSYdgwFPljnBdSdXZhGpe.z86NeNf%2F%2FT9Rn2t9MAaf3%2B4YAnXGsvSbb3nAh0spqZw; XSRF-TOKEN=JtmKfwWOhxxHxtyYR%2B2HdPSfW8e8T7ofUeROE%3D

Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Accept, Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Origin:http://rsm.local:3000
Connection:keep-alive
Content-Length:914
Content-Type:application/json; charset=utf-8
Date:Fri, 06 Dec 2013 15:04:53 GMT

但是,当使用相同的配置执行 POST 或 DELETE 时,cookie 永远不会发送。

这是一个飞行前选项请求的示例(不应该发送任何凭据)

Request URL:http://api.rsm.local:3001/api/v1/articles
Request Method:OPTIONS
Status Code:200 OK

Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:api.rsm.local:3001
Origin:http://rsm.local:3000
Referer:http://rsm.local:3000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)    Chrome/31.0.1650.63 Safari/537.36

Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Accept, Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,POST,PUT,DELETE,OPTIONS
Access-Control-Allow-Origin:http://rsm.local:3000
Allow:GET,POST,PUT,HEAD,DELETE,TRACE,COPY,LOCK,MKCOL,MOVE,PROPFIND,PROPPATCH,UNLOCK,REPORT,MKACTIVITY,CHECKOUT,MERGE,M-SEARCH,NOTIFY,SUBSCRIBE,UNSUBSCRIBE,PATCH
Connection:keep-alive
Content-Length:154
Content-Type:text/html; charset=utf-8
Date:Fri, 06 Dec 2013 15:04:23 GMT

所以这个选项请求似乎说“是的,接受 POST 并且源 URL 匹配”

但是 subsequest POST 请求缺少 Cookie

Request URL:http://api.rsm.local:3001/api/v1/articles

Request Headers
POST http://api.rsm.local:3001/api/v1/articles HTTP/1.1
Accept: application/json, text/plain, */*
Referer: http://rsm.local:3000/
Origin: http://rsm.local:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)    Chrome/31.0.1650.63 Safari/537.36
Content-Type: application/json;charset=UTF-8
Request Payload
...
...
...

这里和网络上的其他地方有很多线程似乎都建议使用我拥有的配置,但仍然没有通过 POST/DELETE 发送凭据。

我现在几乎被困住了,希望另一双眼睛能看到什么?

为什么 GET 可以,而 POST 不行?

我在使用 Chrome 和 FireFox 的 Ubuntu 工作站上 - 两者都不发送凭据。

谢谢。

【问题讨论】:

可能有帮助:***.com/questions/16882245/… 我很确定我已经涵盖了所有这些要点。 withCredentials 已设置,.domain.com 通配符类型会话 cookie 已设置。 【参考方案1】:

我找到了适合我的解决方案。

我正在使用 ExpressJS csrf()、passortjs 和 CORS 标头的组合。

csrf() 失败,这使其他一切都变得糟糕,并导致浏览器在控制台中显示没有凭据的标题。

解决方案是在 connect 的 defaultValue 函数中再添加一个请求类型查找。

我创建了一个新的并像这样使用它:

function csrfValue(req) 
        return (req.body && req.body._csrf)
            || (req.query && req.query._csrf)
            || (req.headers['x-csrf-token'])
            || (req.headers['x-xsrf-token'])
            || (req.cookies['XSRF-TOKEN']);
    

app.use(express.csrf(value: csrfValue));

这使一切正常。

我还发现使用 Restangular 可以为 x-xsrf-token 设置自定义标头,但只有 Chrome 会设置 - FireFox 不会。

所以我选择了 csrfValue() 解决方案。

干杯。

【讨论】:

以上是关于CORS AngularJS 不使用 POST 或 DELETE 发送 Cookie/凭据,但 GET OK的主要内容,如果未能解决你的问题,请参考以下文章

在 angularjs 中使用 $http.post() 时出现 CORS 问题

AngularJS on Rails 中的 CORS 问题

AngularJS和rails cors标头不起作用

angularjs简单实现$http.post(CORS)跨域

AngularJS 和 sinatra CORS

AngularJS 的 CORS 错误仅在 FireFox 中发布