将Laravel Test 7和Laravel Passport 9.3与Personal Access Client一起使用会产生异常“试图获取非对象的属性'id'”

如何解决将Laravel Test 7和Laravel Passport 9.3与Personal Access Client一起使用会产生异常“试图获取非对象的属性'id'”

我正在与无状态API一起设计自定义身份验证方案(基于公钥),并确定Passport将满足对身份验证后请求的需求。

假设身份验证成功,并且用户已通过身份验证,则他们将收到个人访问令牌,并将该令牌用于所有其他请求。我遇到的问题(仍然是经过各种论坛和Stack Overflow的大量搜索之后)是,当使用Laravel的内置测试套件时,在createToken()方法上,它会生成一个(公认的常见)异常:

“ ErrorException:试图获取非对象的属性'id'”。

我能够通过Tinker手动创建用户,并通过Tinker创建令牌。但是,在验证后尝试自动执行此过程时遇到问题。

这是验证后的相关代码段:

            Auth::login($user);
            $user = Auth::user();
            $tokenResult = $user->createToken('Personal Access Token');
            $token = $tokenResult->token;

            $token->expires_at = Carbon::now()->addWeeks(1);
            $token->save();            

            return response()->json([
                "access_token" => $tokenResult->accessToken,"token_type" => "Bearer","expires_at" => Carbon::parse(
                    $tokenResult->token->expires_at)->toDateTimeString()
            ],200);

我已手动对用户调用Auth :: login,以确保用户已登录,并且Auth :: user()返回用户(不为null)。在执行第三行代码后,以下迷你堆栈跟踪将引发异常(如果需要,我可以提供完整的堆栈跟踪)。

laravel\passport\src\PersonalAccessTokenFactory.php:100
laravel\passport\src\PersonalAccessTokenFactory.php:71
laravel\passport\src\HasApiTokens.php:67
app\Http\Controllers\Auth\LoginController.php:97
laravel\framework\src\Illuminate\Routing\Controller.php:54
laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php:45

通过几次调试运行-即使调用并加载了该类,并且看来通过ClientDispatcher-> Client :: find(id)找到了Client,并在ClientRepository中找到了它,当它进入PersonalAccessTokenFactory时,传入的$ client为null(这解释了为什么找不到$ client-> id的原因,尽管我不知道为什么$ client此时为null)。

protected function createRequest($client,$userId,array $scopes)
{
    $secret = Passport::$hashesClientSecrets ? Passport::$personalAccessClientSecret : $client->secret;

    return (new ServerRequest)->withParsedBody([
        'grant_type' => 'personal_access','client_id' => $client->id,...
}

我已经完成/尝试了文档和其他帖子中的一些指导:

  • 在Tinker中手动创建用户,并通过Tinker创建令牌-此可行
  • 确保用户在尝试生成令牌之前已登录。
  • passport:install(并添加--force选项)
  • 确保的“个人访问客户端”是使用“ passport:client --personal”生成的
  • 确保AuthServiceProvider :: boot()包含ClientID和Client Secret(在.env中)。
  • 迁移:刷新,然后护照:install --force
  • 完全删除Passport,删除所有文件,密钥,迁移和数据库条目,然后进行migration:刷新和重新安装Passport,并生成其他个人访问客户端(即使在护照:安装期间生成了一个) 。

目前还不确定在其他地方可以尝试/还有什么尝试,因此不胜感激!

解决方法

我终于找到了解决方案。该问题是多层次的,部分与有关测试和Passport Personal Access Client的过时的Laravel文档有关。

问题的第一部分与在单元测试中使用特征RefreshDatabase有关。由于这会创建一个具有空数据集的模拟数据库,尽管客户端本身存在于真实数据库和.env文件中,但是在运行测试时,测试不会将那些客户端视为模拟数据库中存在的客户端。要解决此问题,您必须create a client in the setup function在运行测试之前。

public function setUp() : void
{
    parent::setUp();
    $this->createClient(); //Private method->Full code below
}

这解决了有关在测试期间使用空客户端的问题,但是从Laravel 7开始,Laravel添加了Personal Access Clients的要求,即必须将id和客户端机密保存在.env文件中。运行测试时,测试将在.env中看到实际的客户端ID和密码,并且无法使用已创建并存储在模拟数据库中的客户端来验证它们,并返回另一个异常:"Client Authentication Failed".

此问题的解决方案是在主项目目录中创建一个.env.testing文件,将您的.env文件内容复制到其中,并确保以下键与您创建的主要Personal Access Client的值一起存在。从仅用于测试的客户端复制机密(我建议后者)。

 PASSPORT_PERSONAL_ACCESS_CLIENT_ID=1

 PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=unhashed-client-secret-value

然后使用下面的代码,确保$ clientSecret值与.env.testing文件中的键值相同。

private function createClient() : void
{
    $clientRepository = new ClientRepository();
    $client = $clientRepository->createPersonalAccessClient(
        null,'Test Personal Access Client','http://localhost'
    );

    DB::table('oauth_personal_access_clients')->insert([
        'client_id'  => $client->id,'created_at' => new DateTime,'updated_at' => new DateTime,]);

    $clientSecret = 'unhashed-client-secret-value';
    $client->setSecretAttribute($clientSecret);
    $client->save();
}

这将创建一个新客户端,将属性secret设置为变量中的值,并更新模拟数据库密钥以包含相同的值。希望这对遇到同样问题的人有所帮助。

,

另一种防止复制/粘贴源代码的方法是在 setup 方法中调用 artisan 命令。

public function setUp() {
        parent::setUp();
        $this->artisan('passport:install');
}

original here

,

只需使用外观

 public function setUp() {
    parent::setUp();
    Artisan::call('passport:install');}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-