简而言之,我将Angular的数据发布到Laravel后端。 OPTIONS /预检请求看起来不错,但后续的POST失败,说请求的资源中缺少Access-Control-Allow-Origin标头。
我使用Laravel 5和Angular 1.2.26。关于后端中间件的一些进一步文档可以在这里找到:https://laracasts.com/discuss/channels/requests/laravel-5-cors-headers-with-filters。
Laravel中间件:
public function handle($request, Closure $next)
{
return $next($request)->header('Access-Control-Allow-Origin' , 'http://laravel.app:8001')
->header('Access-Control-Allow-Credentials', 'true')
->header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE')
->header('Access-Control-Allow-Headers', 'Content-Type, Accept, Authorization, X-Requested-With')
->header('Access-Control-Max-Age', '28800');
}
Angular config - 我尝试过各种评论代码组合,每次都有相同的结果:
$httpProvider.defaults.useXDomain = true;
//$httpProvider.defaults.withCredentials = true;
//delete $httpProvider.defaults.headers.common["X-Requested-With"];
//$httpProvider.defaults.headers.common["Accept"] = "application/json";
//$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
预检/ OPTIONS:
Remote Address:127.0.0.1:8000
Request URL:http://laravel.app:8000/api/v1/authentication/login
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:laravel.app:8000
Origin:http://laravel.app:8001
Referer:http://laravel.app:8001/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Content-Type, Accept, Authorization, X-Requested-With
Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin:http://laravel.app:8001
Access-Control-Max-Age:28800
Allow:GET,HEAD,POST
Cache-Control:no-cache
Connection:keep-alive
Content-Encoding:gzip
Content-Type:text/html; charset=UTF-8
Date:Mon, 24 Nov 2014 16:01:57 GMT
Server:nginx/1.6.2
Set-Cookie:laravel_session=blahblah; expires=Mon, 24-Nov-2014 18:01:57 GMT; Max-Age=7200; path=/; httponly
Set-Cookie:XSRF-TOKEN=blahblah; expires=Thu, 01-Jan-1970 00:02:00 GMT; Max-Age=-1416844797; path=/; httponly
Transfer-Encoding:chunked
POST:
Remote Address:127.0.0.1:8000
Request URL:http://laravel.app:8000/api/v1/authentication/login
Request Method:POST
Status Code:500 Internal Server Error
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:47
Content-Type:application/json;charset=UTF-8
Host:laravel.app:8000
Origin:http://laravel.app:8001
Referer:http://laravel.app:8001/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65 Safari/537.36
Request Payload
{email: "x", password: "x", rememberMe: false}
email: "x"
password: "x"
rememberMe: false
Response Headers
Cache-Control:no-cache
Connection:keep-alive
Content-Type:text/html; charset=UTF-8
Date:Mon, 24 Nov 2014 16:01:57 GMT
Server:nginx/1.6.2
Transfer-Encoding:chunked
答案 0 :(得分:3)
在单步执行VerifyCsrfToken中间件后,我确定它确实是令牌不匹配。
原因是Angular没有通过标头或帖子中的参数提供CSRF令牌。它适用于GET和OPTIONS请求,因为它们不会对令牌进行验证。
所以,我查看了Angular并且有关于XSRF保护的文档(请参阅https://docs.angularjs.org/api/ng/service/ $ http)以及有关如何添加适当标头的大量讨论(例如https://github.com/angular/angular.js/issues/5122#issuecomment-36157820)。
我没有机会跟随这一切,因为我必须保持我的项目移动,我的特定用例允许我放弃禁用VerifyCsrfToken,因为我在开发过程中只需要CORS。
但希望这会给别人一个解决这个问题的起点。
答案 1 :(得分:2)
我不确定这是否是Laravel和VerifyCsrfToken中间件的问题,但我的问题的根本原因是CSRF令牌验证失败。抛出错误时,不包括新标头。我不清楚这些中间件运行的顺序,也许就是这样,但是,一旦我从中间件堆栈中删除了VerifyCsrfToken,一切都亮了。
答案 2 :(得分:0)
我有问题。如果您使用中间件来设置标头,但在控制器上创建新的响应,Response::json()
,Response::make()
等,则此新对象不会获得由中间件设置的标头。
答案 3 :(得分:0)
我有同样的问题。 在CORS中间件中 添加以下标题。
public function handle($request, Closure $next)
{
//All the domains you want to whitelist
$trusted_domains = ["http://localhost:4200", "http://127.0.0.1:4200", "http://localhost:3000", "http://127.0.0.1:3000"];
if (isset($request->server()['HTTP_ORIGIN'])) {
$origin = $request->server()['HTTP_ORIGIN'];
if (in_array($origin, $trusted_domains)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Access-Control-Allow-Headers: Origin, Content-Type, Authorization, X-Auth-Token,x-xsrf-token');
header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT, DELETE');
}
}
return $next($request);
}