方法 IlluminateAuthRequestGuard::logout 不存在 Laravel Passport [英] Method IlluminateAuthRequestGuard::logout does not exist Laravel Passport

查看:38
本文介绍了方法 IlluminateAuthRequestGuard::logout 不存在 Laravel Passport的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 Laravel Passport 构建 API,我相应地删除了网络路由及其防护

如何测试用户注销?

这是我目前所拥有的:

注销测试

/*** 断言用户可以退出** @return 无效*/公共函数 test_logout(){//$data->token_type = "Bearer"//$data->access_token = "长字符串是为了简洁而被剥离的有效令牌"$response = $this->json('POST', '/api/logout', [], ['授权' =>$data->token_type .' ' .$data->access_token]);$response->assertStatus(200);}

routes/api.php

Route::post('logout', 'AuthLoginController@logout')->name('logout');

控制器方法使用 AuthenticatesUsers 特性,因此保留默认功能

/*** 从应用程序中注销用户.** @param IlluminateHttpRequest $request* @return IlluminateHttpResponse*/公共功能注销(请求 $request){$this->guard()->logout();$request->session()->invalidate();return $this->loggedOut($request) ?: redirect('/');}

<块引用>

错误方法 IlluminateAuthRequestGuard::logout 不存在

Laravel 文档 讨论了颁发和刷新访问令牌,但什么也没说关于撤销它们或执行注销

注意:我正在使用密码授予令牌

注意 2:撤销用户的令牌不起作用

公共函数注销(Request $request){$request->user()->token()->revoke();返回 $this->loggedOut($request);}

第二次断言测试失败

公共函数 test_logout(){$response = $this->json('POST', '/api/logout', [], ['授权' =>$data->token_type .' ' .$data->access_token]);$response->assertStatus(200);//通过$check_request = $this->get('/api/user');$check_request->assertForbidden();//失败}

给定需要认证的默认路由

Route::middleware('auth:api')->get('/user', function (Request $request) {返回 $request->user();});

<块引用>

响应状态码 [200] 不是禁止状态码.

那是怎么回事?以及如何使用 Passport 测试用户注销?

提前致谢

解决方案

正在撤销令牌.是测试不起作用,但原因不明显.

在一次测试中发出多个请求时,您的 Laravel 应用程序的状态不会在请求之间重置.Auth 管理器是 laravel 容器中的一个单例,它保存已解析的 auth 守卫的本地缓存.已解析的 auth 守卫会保留已认证用户的本地缓存.

因此,您对 api/logout 端点的第一个请求将解析身份验证管理器,该管理器解析 API 防护,该防护存储对您将撤销其令牌的已认证用户的引用.

现在,当您向 /api/user 发出第二个请求时,已解析的身份验证管理器将从容器中提取,已解析的 api 防护从其本地缓存中提取,并且相同已解析的用户从警卫的本地缓存中提取.这就是第二个请求通过身份验证而不是失败的原因.

在同一个测试中使用多个请求测试与身份验证相关的内容时,您需要在测试之间重置已解析的实例.此外,您不能只是取消设置已解析的身份验证管理器实例,因为当它再次解析时,它不会定义扩展的 passport 驱动程序.

所以,我发现的最简单的方法是使用反射来取消设置已解析身份验证管理器上受保护的 guards 属性.您还需要在已解析的会话守卫上调用 logout 方法.

我的 TestCase 类中有一个方法,看起来像:

受保护的函数 resetAuth(array $guards = null){$guards = $guards ?: array_keys(config('auth.guards'));foreach ($guards as $guard) {$guard = $this->app['auth']->guard($guard);if ($guard instanceof IlluminateAuthSessionGuard) {$guard->logout();}}$protectedProperty = new ReflectionProperty($this->app['auth'], 'guards');$protectedProperty->setAccessible(true);$protectedProperty->setValue($this->app['auth'], []);}

现在,您的测试将类似于:

公共函数 test_logout(){$response = $this->json('POST', '/api/logout', [], ['授权' =>$data->token_type .' ' .$data->access_token]);$response->assertStatus(200);//直接断言api用户的token被吊销了.$this->assertTrue($this->app['auth']->guard('api')->user()->token()->revoked);$this->resetAuth();//对下一个请求使用已撤销的令牌进行断言将不起作用.$response = $this->json('GET', '/api/user', [], ['授权' =>$data->token_type .' ' .$data->access_token]);$response->assertStatus(401);}

Am using Laravel Passport to build an API, I removed the web routes and its guard accordingly

How can I test user logout?

This is what I have so far:

Logout Test

/**
 * Assert users can logout
 *
 * @return void
 */
public function test_logout()
{
    // $data->token_type = "Bearer"
    // $data->access_token = "Long string that is a valid token stripped out for brevety"
    $response = $this->json('POST', '/api/logout', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(200);
}

routes/api.php

Route::post('logout', 'AuthLoginController@logout')->name('logout');

The controller method uses the AuthenticatesUsers trait so the default function is kept

/**
 * Log the user out of the application.
 *
 * @param  IlluminateHttpRequest  $request
 * @return IlluminateHttpResponse
 */
public function logout(Request $request)
{
    $this->guard()->logout();

    $request->session()->invalidate();

    return $this->loggedOut($request) ?: redirect('/');
}

Error Method IlluminateAuthRequestGuard::logout does not exist

The Laravel Documentation talks about issuing and refreshing access tokens but nothing about revoking them or performing logout

Note: am using password grant tokens

Note 2: revoking the user's token doesn't work

public function logout(Request $request)
{
    $request->user()->token()->revoke();
    return $this->loggedOut($request);
}

Test Fails on second assertion

public function test_logout()
{
    $response = $this->json('POST', '/api/logout', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(200); // Passes
    $check_request = $this->get('/api/user');
    $check_request->assertForbidden(); // Fails
}

Given the default route requiring authentication

Route::middleware('auth:api')->get('/user', function (Request $request) {
    return $request->user();
});

Response status code [200] is not a forbidden status code.

So what's going on? and how can I test user logout with Passport?

Thanks in advance

解决方案

Revoking the token is working. It is the test that is not working, but it is not obvious why.

When making multiple requests in one test, the state of your laravel application is not reset between the requests. The Auth manager is a singleton in the laravel container, and it keeps a local cache of the resolved auth guards. The resolved auth guards keep a local cache of the authed user.

So, your first request to your api/logout endpoint resolves the auth manager, which resolves the api guard, which stores a references to the authed user whose token you will be revoking.

Now, when you make your second request to /api/user, the already resolved auth manager is pulled from the container, the already resolved api guard is pulled from it's local cache, and the same already resolved user is pulled from the guard's local cache. This is why the second request passes authentication instead of failing it.

When testing auth related stuff with multiple requests in the same test, you need to reset the resolved instances between tests. Also, you can't just unset the resolved auth manager instance, because when it is resolved again, it won't have the extended passport driver defined.

So, the easiest way I've found is to use reflection to unset the protected guards property on the resolved auth manager. You also need to call the logout method on the resolved session guards.

I have a method on my TestCase class that looks something like:

protected function resetAuth(array $guards = null)
{
    $guards = $guards ?: array_keys(config('auth.guards'));

    foreach ($guards as $guard) {
        $guard = $this->app['auth']->guard($guard);

        if ($guard instanceof IlluminateAuthSessionGuard) {
            $guard->logout();
        }
    }

    $protectedProperty = new ReflectionProperty($this->app['auth'], 'guards');
    $protectedProperty->setAccessible(true);
    $protectedProperty->setValue($this->app['auth'], []);
}

Now, your test would look something like:

public function test_logout()
{
    $response = $this->json('POST', '/api/logout', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(200);

    // Directly assert the api user's token was revoked.
    $this->assertTrue($this->app['auth']->guard('api')->user()->token()->revoked);

    $this->resetAuth();

    // Assert using the revoked token for the next request won't work.
    $response = $this->json('GET', '/api/user', [], [
         'Authorization' => $data->token_type . ' ' . $data->access_token
    ]);
    $response->assertStatus(401);
}

这篇关于方法 IlluminateAuthRequestGuard::logout 不存在 Laravel Passport的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆