在安装 tymon/jwt-auth 后的 laravel Backend REST API 应用程序中再次遇到 CORS 错误

Posted

技术标签:

【中文标题】在安装 tymon/jwt-auth 后的 laravel Backend REST API 应用程序中再次遇到 CORS 错误【英文标题】:In laravel Backend REST API app after installing tymon/jwt-auth again suffer CORS error 【发布时间】:2020-03-21 20:14:17 【问题描述】:

我使用从 Laravel 后端 REST API 读取的数据制作 @vue/cli 4.0.5 / vuex 3 应用程序,并使用 /barryvdh/laravel-cors(0.11.4) 来解决 CORS 问题: 它工作正常,直到我添加了 tymon/jwt-auth(1.0.0) 并实现了这个库,我在包含的库中遇到了一些问题,但是在 我安装了它我又遇到了CORS错误,比如:

VM15:1 OPTIONS http://local-ctasks-api.com/api/login 403 (Forbidden)
(anonymous) @ VM15:1
dispatchXhrRequest @ xhr.js?b50d:172
xhrAdapter @ xhr.js?b50d:11
dispatchRequest @ dispatchRequest.js?5270:59
Promise.then (async)
request @ Axios.js?0a06:53
Axios.<computed> @ Axios.js?0a06:78
wrap @ bind.js?1d2b:9
eval @ index.js?4360:135
login @ index.js?4360:124
wrappedActionHandler @ vuex.esm.js?2f62:747
dispatch @ vuex.esm.js?2f62:438
boundDispatch @ vuex.esm.js?2f62:332
authenticate @ Login.vue?7463:164
submit @ Login.vue?2447:24
invokeWithErrorHandling @ vue.runtime.esm.js?2b0e:1854
invoker @ vue.runtime.esm.js?2b0e:2179
original._wrapper @ vue.runtime.esm.js?2b0e:6911
login:1 Access to XMLHttpRequest at 'http://local-ctasks-api.com/api/login' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

composer.json:


    "name": "laravel/laravel",
    "type": "project",
    "description": "The Laravel Framework.",
    "keywords": [
        "framework",
        "laravel"
    ],
    "license": "MIT",
    "require": 
        "php": "^7.1.3",
        "barryvdh/laravel-cors": "^0.11.4",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "^5.8.0",
        "laravel/tinker": "^1.0",
        "tymon/jwt-auth": "^1.0.0",
        "wboyz/laravel-enum": "^0.2.1"
    ,
    "require-dev": 
        "fzaninotto/faker": "^1.8",
        "mockery/mockery": "^1.0",
        "nunomaduro/collision": "^2.0",
        "phpunit/phpunit": "^7.0"
    ,
    "config": 
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    ,
    "extra": 
        "laravel": 
            "dont-discover": []
        
    ,
    "autoload": 
        "psr-4": 
            "App\\": "app/"
        ,
        "classmap": [
            "database/seeds",
            "database/factories"
        ]
    ,
    "autoload-dev": 
        "psr-4": 
            "Tests\\": "tests/"
        
    ,
    "minimum-stability": "dev",
    "prefer-stable": true,
    "scripts": 
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi"
        ]
    

app/Http/Kernel.php:

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel

    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \Barryvdh\Cors\HandleCors::class,  // I ADDED THIS LINE !
    ];

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
            'cors',  // ALSO I ADDED THIS LINE - fount in net!
        ],
    ];

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];


    protected $middlewarePriority = [
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\Authenticate::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];

在 config/auth.php 中:

<?php

return [

    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],


    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'jwt', // LINE WITH JWT as driver !
            'provider' => 'users',
        ],

    ],

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],

    ],

    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],

    'password_timeout' => 10800,

];

配置/cors.php:

<?php

return [

    'supportsCredentials' => false,
    'allowedOrigins' => ['*'],
    'allowedHeaders' => ['Content-Type', 'X-Requested-With'],
    'allowedMethods' => ['*'], // ex: ['GET', 'POST', 'PUT',  'DELETE']
    'exposedHeaders' => [],
    'maxAge' => 0,

];

在 config/app.php 中:

    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Notifications\NotificationServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,
        Barryvdh\Cors\ServiceProvider::class,  // CORS ADDED LINE

        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        // App\Providers\BroadcastServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

//        Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class, // I HAD PROBLEMS WITH THIS OPTION - SO I COMMENTED it

    ],


    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Arr' => Illuminate\Support\Arr::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
        'Bus' => Illuminate\Support\Facades\Bus::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Notification' => Illuminate\Support\Facades\Notification::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'Str' => Illuminate\Support\Str::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
        'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class, // JWT ADDED !
        'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,

    ],

在网上搜索我发现了一些可能的决定,但都失败了...... 我错过了什么以及如何让它运行?

更新 #2: 经过一番搜索,我应用了下一个更改: 在我设置的后端 API 应用的 config/cors.php 中:

supportsCredentials' => true,

在 axios 请求中的 vue 端:

let config = 
    withCredentials:true,
    headers: 
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
    


axios.post(apiUrl + '/login', userCredentials, config)
    .then((response) => 

在 app/Http/Kernel.php 中:

protected $middleware = [
    ...
    \Barryvdh\Cors\HandleCors::class,
];

看起来 GET 请求工作正常,POST 请求不工作。

所以在我的后端 API 路由/api.php 中有 3 条路由:

Route::post('login', 'API\UserController@login', ['except' => []]);
Route::post('register', 'API\UserController@register');
Route::get('get_users_stats/id', 'API\UserController@get_users_stats');

只有最后一个工作正常。

在 config/cors.php 我有选项:

'supportsCredentials' => true,
'allowedOrigins' => ['*'],
'allowedHeaders' => ['Content-Type', 'X-Requested-With'],
'allowedMethods' => ['*'], 
'exposedHeaders' => [],
'maxAge' => 0,

但如果要更改选项:

'allowedMethods' => ['POST'], // ex: ['GET', 'POST', 'PUT',  'DELETE']

那么 POST / GET DO NOT WORK 并引发 CORS 错误

另外,由于 POST 请求需要提供 csrf 令牌,这可能是问题吗?

【问题讨论】:

抱歉,不知道为什么会出错以及如何解决? 请看更新#2 对不起,没有可能的决定?是否有一些示例/演示可用于 vue/cli / Laravel 后端 REST API,使用 jwt 和 CORS 问题得到解决?上传/安装并尝试在本地运行会很有趣... 【参考方案1】:

我设法通过几个附加选项修复了这个错误: 在 app/Http/Kernel.php 中:

protected $middleware = [ 
    \Barryvdh\Cors\HandleCors::class, // MUST BE FIRST POSITION!
    \App\Http\Middleware\TrustProxies::class,
    ...
];

在 .env 中:

ALLOWED_ORIGINS= '*' // Locally

在 config/cors.php 中:

'supportsCredentials' => true,
'allowedOrigins' => [env('ALLOWED_ORIGINS')], // '*' for local
'allowedOriginsPatterns' => [],
'allowedHeaders' => ['*'],
'allowedMethods' => ['*'],
'exposedHeaders' => [],
'maxAge' => 0,

在提供程序块中的 config/app.php 注释中:

'providers' => [
    ...
//        Tymon\JWTAuth\Providers\JWTAuthServiceProvider::class,
    ...
    'aliases' => [
        'JWTAuth' => Tymon\JWTAuth\Facades\JWTAuth::class,
        'JWTFactory' => Tymon\JWTAuth\Facades\JWTFactory::class,

在 config/jwt.php 中:

'jwt' => Tymon\JWTAuth\Providers\JWT\Namshi::class,
'auth' => Tymon\JWTAuth\Providers\Auth\Illuminate::class,
'storage' => Tymon\JWTAuth\Providers\Storage\Illuminate::class,

在 app/User.php 中:

use Tymon\JWTAuth\Contracts\JWTSubject;
...
class User extends Authenticatable implements JWTSubject

     ...
     public function getJWTIdentifier()
    
        return $this->getKey();
    
    public function getJWTCustomClaims()
    
        return [];
    

在客户端:

let config = 
    withCredentials:true, // must be false without JWT used
    headers: 
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin': '*',
    

console.log('login config::')
console.log(config)

axios.post(apiUrl + '/login', userCredentials, config)
    .then((response) => 
        console.log('login response::')

现在检查。看来,它有效...

【讨论】:

以上是关于在安装 tymon/jwt-auth 后的 laravel Backend REST API 应用程序中再次遇到 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

PHP Laravel 5.7 Tymon/jwt-auth 未安装

laravel composer install 无法解决 tymon/jwt-auth 的可安装包

Laravel 7.0 - tymon/jwt-auth - 检查令牌是不是有效

Laravel 8 tymon/jwt-auth 使另一个用户的令牌无效

tymon/jwt-auth Laravel:无法验证令牌签名

升级后的 jwt-auth - 从请求令牌中获取用户