Laravel 护照出现 401 Unauthenticated 错误

Posted

技术标签:

【中文标题】Laravel 护照出现 401 Unauthenticated 错误【英文标题】:Laravel passport gives 401 Unauthenticated error 【发布时间】:2018-05-15 15:14:15 【问题描述】:

我正在使用 Laravel 护照进行 API 身份验证,当我将它与一个数据库一起使用时它可以完美运行,但在使用多个数据库时会给出 401

我在做什么:

我有一个多租户数据库,主数据库有用户、角色和所有 OAuth 表。 当我创建一个具有管理员角色的用户时,它将创建具有管理员名称的新数据库,它将创建具有用户、角色和所有 OAuth 表的子数据库。子数据库的oauth_clients 将从主数据库复制密码授予令牌和个人访问令牌并插入子数据库,并在oauth_personal_access_clients 中插入client_id

我正在执行passport:install 命令执行的所有程序。 (如果我没有遗漏什么)。

当我使用主数据库中的凭据登录时,它运行良好,真正的问题是当我使用子数据库中的凭据登录时,我可以从参数client_code 获取子数据库,我使用email 输入,password 登录时。

它允许我从子数据库登录,但我收到 401 Unauthenticated 错误,登录时获取访问令牌,并且我在从 Angular 前面登录后的每个请求上传递带有 BearerAuthentication 标头。

不知道我在这里缺少什么。

DBConnection 中间件

DBConnection 中间件在登录后为每个请求设置连接,

public function handle($request, Closure $next)
    
        if ( $request->method() != 'OPTIONS' )             
            $this->access_code = $request->header('access-code'); 
            if ( $this->access_code != '' && $this->access_code != 'sa'  ) 
                app('App\Http\Controllers\Controller')->setDB(AppHelper::DB_PREFIX.$this->access_code);
             else 
                app('App\Http\Controllers\Controller')->setDB(AppHelper::DB_DEFAULT);
            
        
        return $next($request);
    

DBConnection 动态设置database.php 中的默认数据库,为此,我调用在Controller.php 上创建的setDB 方法

setDB Controller.php

public function setDB($database='') 
      $config = app()->make('config');
      $connections = $config->get('database.connections');
      $default_connection = $connections[$config->get('database.default')];
      $new_connection = $default_connection;
      $new_connection['database'] = $database;
      $config->set('database.connections.'.$database, $new_connection);
      $config->set('database.default', $database);
  

是否可以将passport 与 2 个不同的数据库一起用于相同的代码?

Laravel 5.4 Passport 4.0 Angular 4.4 在前端

【问题讨论】:

你如何在数据库之间切换以及你的标题里面到底有什么?这听起来像是其中之一的问题。 @tprj29 我创建了一个设置数据库配置的中间件,我在路由参数中传递了一个数据库名称,我认为它没有问题,因为登录完美,但登录后出现问题,它开始给出 401 错误,在前面使用 Angular 4 这听起来确实像一个标题问题,因为标题Authentication只有在登录后才需要。而且由于登录和获取不记名令牌可以根据您的需要完美运行。你能告诉我们你的标题Authentication有什么价值吗? @tprj29 授权与登录传递的相同 代码会有所帮助,因为如果没有 anny 代码片段,很难看出哪里出错了 【参考方案1】:

回答你的问题:是的,你可以!

在我们的中间件中,我们这样做:

config([
  'database.connections.tenant.schema' => $tenant
]);

DB::connection('tenant')->statement("SET search_path = $tenant");

在我看来,您的 search_path 设置不正确。这可以解释为什么您会得到 401。因为 Laravel Passport 在错误的数据库中搜索,在您的用户表中找不到正确的令牌。

来自 PostgreSQL 文档 (https://www.postgresql.org/docs/9.1/static/runtime-config-client.html):

搜索路径(字符串)

此变量指定在未指定架构的简单名称引用对象(表、数据类型、函数等)时搜索架构的顺序。当不同模式中存在同名对象时,使用在搜索路径中首先找到的对象。不在搜索路径中的任何架构中的对象只能通过使用限定(点分)名称指定其包含架构来引用。

【讨论】:

我没有使用PostgreSQL,我使用的是mysql 在您处理查询的模型中,您可以记录使用的连接吗?我认为模型内部没有正确管理连接。 如果我不使用passport 连接完美【参考方案2】:

这是 CORS 问题。 OPTIONS 请求不传递授权标头。

如果源与主机不同,浏览器将在任何其他请求之前发送 OPTIONS。

如果没有设置 CORS 中间件,Laravel 会返回 401 状态。

因此,对于 RESTful 架构,如果客户端应用程序主机与 API 的主机不同,您必须使用 CORS 中间件。

你可以使用这个: barryvdh/laravel-cors

$ composer require barryvdh/laravel-cors

例子:

App\Http\Kernel.php

protected $routeMiddleware = [
    ...
    'auth.cors' => \Barryvdh\Cors\HandleCors::class,
    ...
];

web.php

Route::group([
    'prefix' => 'api',
    'middleware' => [
        'auth.cors'
    ]
], function () 
    Route::post('user/authenticate', 'UserController@authenticate');
);

如果 CORS 中间件正常工作,浏览器将收到 OPTIONS 请求的状态 200 并使用有效负载触发初始请求。

【讨论】:

他没有发送 OPTIONS 请求 - 他的中间件正在检查方法 other 而不是 OPTIONS

以上是关于Laravel 护照出现 401 Unauthenticated 错误的主要内容,如果未能解决你的问题,请参考以下文章

在内部生成 laravel 护照令牌。 401错误未经授权

Laravel 护照 oauth 路线总是返回 401 未经授权

在 Laravel 护照、vueJS 和 Axios 中获得未经授权的 401

在Laravel护照,vueJS和Axios中未经授权获得401

Laravel 护照公共 api 路线

Laravel Passport使用Axios 401未认证的API消耗自己的API.