我有一个ExpressJS API服务器和一个在本地开发中运行的带有AngularJS应用程序的ExpressJS。
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
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并且Origin 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工作站上 - 两者都不发送凭据。
感谢。
答案 0 :(得分: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()解决方案。
干杯。