首页 文章

Angular CORS请求未能通过Laravel后端,但预检看起来不错

提问于
浏览
3

简而言之,我将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配置 - 我尝试了注释代码的各种组合,每次都有相同的结果:

$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";

预检/选项:

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

4 回答

  • 2

    在单步执行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 .

    但希望这会给别人一个解决这个问题的起点 .

  • 0

    我不确定这是否是Laravel和VerifyCsrfToken中间件的问题,但我的问题的根本原因是CSRF令牌验证失败 . 抛出错误时,不包括新标头 . 我不清楚这些中间件运行的顺序,也许就是这样,但是,一旦我从中间件堆栈中删除了VerifyCsrfToken,一切都亮了起来 .

  • 0

    我有问题 . 如果您使用中间件来设置Headers,但在控制器上创建一个新的Response, Response::json()Response::make() 等,则此新对象不会获得由中间件设置的标头 .

  • 3

    我有同样的问题 . 在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);
    }
    

相关问题