Laravel 5.2 CORS,GET不适用于预检OPTIONS

时间:2016-01-12 16:34:15

标签: php laravel cors vue.js laravel-5.2

可怕的CORS错误:

  

阻止跨源请求:同源策略禁止读取   http://localhost/mysite/api/test处的远程资源。 (原因:CORS   标题' Access-Control-Allow-Origin'丢失)。

Laravel路线:

$router->group(['prefix' => 'api', 'middleware' => 'cors'], function ($router) {
    $router->get('/test', 'MyController@myMethod');
});

Laravel Cors Middlware:

public function handle($request, Closure $next)
    {
        header('Access-Control-Allow-Origin: *');

        // ALLOW OPTIONS METHOD
        $headers = [
            'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Headers' => 'Content-Type, X-Auth-Token, Origin, Authorization'
        ];
        if ($request->getMethod() == "OPTIONS") {
            // The client-side application can set only headers allowed in Access-Control-Allow-Headers
            return Response::make('OK', 200, $headers);
        }

        $response = $next($request);
        foreach ($headers as $key => $value)
            $response->header($key, $value);
        return $response;
    }

Laravel Kernel:

 protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'cors' => \App\Http\Middleware\CORS::class
    ];

相关.htaccess:

RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

相关的Vue.js:

 new Vue({
        el: '#app',
        data: {
           //data here
        },
        http: {
            headers: {
                "Authorization": "Basic " + "apiKeyHere"
            }
        },
        methods: {
            mymethod: function (e)
            {
                e.preventDefault();
                this.$http.get('http://localhost/mysite/api/test').then(
                        function (response)
                        {
                          //do something
                        }
                )
            }
        }
    });

如果我取出Authorization标头选项,则请求有效。

我也试过https://github.com/barryvdh/laravel-cors但仍然没有快乐。 任何帮助表示赞赏!

9 个答案:

答案 0 :(得分:22)

显然不是理想的解决方案,但它起作用。我已经将它添加到我的routes.php文件的顶部:

header('Access-Control-Allow-Origin: *');
header( 'Access-Control-Allow-Headers: Authorization, Content-Type' );

在没有黑客的情况下让它工作真是太好了......唉。

更新:原来是IIS相关。我最终在web.config文件中设置了标题,现在CORS可以在不破坏routes.php文件的情况下工作。

<httpProtocol>
    <customHeaders>
       <add name="Access-Control-Allow-Headers" value="Origin, Authorization, X-Requested-With, Content-Type, Accept" />
       <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
    </customHeaders>
</httpProtocol>

如果要限制访问权限,可以添加出站规则:

      <outboundRules>
          <clear />
                <rule name="AddCrossDomainHeader">
                    <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
                    <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
                        <add input="{HTTP_ORIGIN}" pattern="(http(s)?://((.+\.)?somesite\.com|(.+\.)?anothersite\.org))" />
                    </conditions>
                    <action type="Rewrite" value="{C:0}" />
                </rule>
      </outboundRules>

答案 1 :(得分:14)

我解决了我的问题,只需在我的routes.php Laravel 5.2上添加这些行 对于大于5.2的routes / web.php

header('Access-Control-Allow-Origin:  *');
header('Access-Control-Allow-Methods:  POST, GET, OPTIONS, PUT, DELETE');
header('Access-Control-Allow-Headers:  Content-Type, X-Auth-Token, Origin, Authorization');

在全局HTTP中间件堆栈中注册Cors中间件

protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \App\Http\Middleware\CorsMiddleware::class
];

答案 2 :(得分:6)

您的中间件还可以,但您需要在全球HTTP中间件堆栈中注册Cors中间件。

protected $middleware = [
    \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    \App\Http\Middleware\CorsMiddleware::class
];

答案 3 :(得分:3)

这个问题确实来自于预检请求,但是当我们谈论Laravel时,处理方式需要一些额外的解释 - 主要是OPTIONS请求被路由(其他答案反而是PHP)方式,而不是Laravel方式),所以,你必须将它添加到你的路线才能成功:

Route::options('/{any}', function(){ return ''; })->where('any', '.*');

现在,让我们迎合所有其他方法 - 创建CORS中间件:

namespace App\Http\Middleware;

use Closure;

class Cors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', '*')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE');
    }
}

最后,对于给定的路由,请使用该中间件:

Route::put('/test', function(){ echo('test'); })->with('cors');

答案 4 :(得分:2)

你可以绕过这个没有像Barryvdh \ Cors for Laravel这样与JWT AUTH无法正常工作的中间件,我已经在内核实例化之前在Laravel的index.php中添加了以下语句

header('Access-Control-Allow-Origin: http://localhost:8001');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token,Authorization');
header('Access-Control-Allow-Credentials: true');

之前加上这个
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

这也适用于JWT AUTH。 请注意,在Access-Control-Allow-Headers中,您应该包含授权,否则授权标头将不允许您的accesstoken,因此JWT AUTH将失败。 快乐编码。

答案 5 :(得分:0)

我的解决方案:

$router->group(['prefix' => 'api', 'middleware' => 'cors'], function ($router){
    $router->options('{param1?}/{param2?}/{param3?}', function () {});
});

答案 6 :(得分:0)

即使将中间件直接放入$middleware而不是$routeMiddleware或只是在app.php中全局定义标头,这都是一个可怕的决定,因为它将暴露所有端点使用新的CORS政策,以防万一您只想将API的一部分公开给第三方解决方案。

更好的解决方案是仅允许OPTIONS调用在所有端点上通过,并且仍然通过$routeMiddleware重定向其他HTTP方法,以便仅在一部分端点上限制CORS策略。

因此,构建两个中间件:

Cors.php

 <?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)
          ->header('Access-Control-Allow-Origin', '*')
          ->header('Access-Control-Allow-Methods', '*')
          ->header('Access-Control-Allow-Headers', '*');
    }
}

OptionsCors.php

<?php

namespace App\Http\Middleware;

use Closure;

class OptionsCors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
      if($request->isMethod('OPTIONS')) {
        return $next($request)
          ->header('Access-Control-Allow-Origin', '*')
          ->header('Access-Control-Allow-Methods', '*')
          ->header('Access-Control-Allow-Headers', '*');
      }
      return $next($request);
    }
}

app / Http / Kernel.php

<?php 
namespace App\Http
{
    class Kernel extends \Illuminate\Foundation\Http\Kernel
    {
        protected $middleware = [
            // ...
            'App\Http\Middleware\OptionsCors',
        ];
        protected $middlewareGroups = [
            'web' => [
                 // ...
            ], 
            'api' => [
                'App\Http\Middleware\UseApiGuard', 
                'throttle:60,1', 
                'bindings'
            ]
        ];
        protected $routeMiddleware = [
            // ...
            'cors' => 'App\Http\Middleware\Cors', 
        ];
    }

}

现在,在您的路由中,您将完全控制收紧的CORS政策将暴露哪些端点:

Route::namespace('Api')->middleware(['cors'])->group(function () {

    Route::get('api/im_open', 'TestController@ping');

});
Route::namespace('Api')->group(function () {

    Route::get('api/im_closed', 'TestController@ping');

});

答案 7 :(得分:0)

我通过在 bootstrap/app.php 中添加标题轻松解决了我的问题

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: *');
header('Access-Control-Allow-Headers: *');

答案 8 :(得分:-1)

此答案基于此articlebarryvdh/laravel-cors中间件库,可用于解决问题(跨源资源共享)。

第1步安装它:

composer require barryvdh/laravel-cors

第2步:发布图书馆的供应商文件:

php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider"

第3步在第2步中运行的命令会将cors.php文件复制到config目录,如下所示:

return [

/*
|--------------------------------------------------------------------------
| Laravel CORS
|--------------------------------------------------------------------------
|
| allowedOrigins, allowedHeaders and allowedMethods can be set to array('*')
| to accept any value.
|
*/

'supportsCredentials' => false,
'allowedOrigins' => ['*'],// ex: ['abc.com', 'api.abc.com']
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],// ex: ['GET', 'POST', 'PUT', 'DELETE']
'exposedHeaders' => [],
'maxAge' => 0,

];

对于allowedOrigins,值可以是['*'],表示请求的来源可以来自任何域,也可以是特定域的数组,这些域可以是我们允许发送请求的来源到我们的api,就像['first.com', 'second.com', 'register.third.com']

一样

以及allowedMethods可以是['*'],也可以是允许的HTTP verbs列表,例如['POST', 'GET']

第4步注册cors中间件。打开app/Http/kernel.php并将HandleCors课程添加到$routeMiddleware,如下所示:

protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'cors' => \Barryvdh\Cors\HandleCors::class, // add this line to enable cors to your routes
];

第5步现在,您可以将laravel-cors中间件添加到您想要的任何路由中。例如,在Routes/api.php我会这样做:

Route::apiResource('category', 'CategoryController')->middleware('cors');
Route::apiResource('product', 'ProductController')->middleware('cors');