方法Illuminate \ Auth \ RequestGuard :: logout不存在Laravel Passport [英] Method Illuminate\Auth\RequestGuard::logout does not exist Laravel Passport

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

问题描述

我是使用 Laravel Passport 来构建API的,因此我相应地删除了网络路由及其保护措施

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

如何测试用户注销?

这是我到目前为止所拥有的:

This is what I have so far:

注销测试

/**
 * 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', 'Auth\LoginController@logout')->name('logout');

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

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

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

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

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

错误方法Illuminate \ Auth \ RequestGuard :: logout不存在

Error Method Illuminate\Auth\RequestGuard::logout does not exist

Laravel文档讨论了发行和刷新访问令牌,但没有任何内容关于撤消他们或执行注销

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

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

测试在第二个断言上失败

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();
});

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

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

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

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

预先感谢

推荐答案

撤消令牌有效.这是测试无效的方法,但原因并不明显.

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

在一个测试中发出多个请求时,不会在两次请求之间重置laravel应用程序的状态.身份验证管理器是laravel容器中的一个单例,它保留已解析身份验证防护的本地缓存.已解决的身份验证防护会保留已身份验证用户的本地缓存.

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.

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

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.

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

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.

在同一测试中测试具有多个请求的auth相关内容时,您需要在测试之间重置已解析的实例.另外,您不能仅取消设置已解析的身份验证管理器实例,因为再次对其进行解析时,将不会定义扩展的 passport 驱动程序.

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.

因此,我找到的最简单的方法是使用反射在已解析的身份验证管理器上取消设置受保护的 guards 属性.您还需要在已解决的会话防护上调用 logout 方法.

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.

我的TestCase类上有一个类似于以下内容的方法:

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 \Illuminate\Auth\SessionGuard) {
            $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);
}

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

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