[大神勿进菜鸟参考] Laravel6 passport API 一个用户只有唯一 token

和我一样的菜鸟可以参考参考哈。

一开始用的原生的API,水平有线,用的自己都不放心,后来思来想去就用passport试试吧。
折腾到感觉OK了,然后就去看数据库,不看不知道,一看吓一跳。
我有强迫症那么多冗余数据,如果访问量大了起来,好可怕。
我就想每个用户只有也仅有自己的对应TOKEN数据,其他的我不要。
于是就折腾出了以下的方式来实现。

一、设置过期时间,方便调试

app\Providers\AuthServiceProvider.php

密码授权模式

public function boot()
    {
        $this->registerPolicies();
        Passport::routes(); //接口认证路由
        //这里调试的时候可以按分钟设置,这三个一定要一直,否则会出现token过期时间不统一的情况,还有就是明明过期了,居然还能用
        //对于强迫症来说,不可接受
        Passport::tokensExpireIn(now()->addYear(1));
        Passport::refreshTokensExpireIn(now()->addYear(1));
        Passport::personalAccessTokensExpireIn(now()->addYear(1));
    }

其他的配置,按照官方的默认的来就可以。

二、大概流程思路

【大神勿进 仅供菜鸟参考】Laravel6 passportAPI认证 禁止产生无效数据 一个用户只有一个token

三、控制器部分(核心部分)

<?php

namespace App\Http\Controllers;

use App\Http\Requests\LoginUserRequest;
use App\Http\Requests\RegisterUserRequest;
use App\Model\User;
use GuzzleHttp\Client;
use Hash;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class UserController extends Controller
{
    public $token;

    public function register(RegisterUserRequest $request)
    {
        User::create([
            'name' => $request['name'],
            'email' => $request['email'],
            'password' => Hash::make($request['password'])
        ]);
        return response([
            'message' => '注册成功',
        ]);
    }

    public function login(LoginUserRequest $request)
    {
        //适合全新的项目,如果已经有相关数组存在,个人觉得可以挑选最大日期的可用token来加以处理
        //这样做的好处可以确保用户token的唯一性,不会再表里存在大量无用数据,而且web也可以用
        //主要构思就是确保user表里的remember_token、oauth_access_tokens表的id、oauth_refresh_tokens表里的access_token_id,这三个数值保持一致
        $user = User::where('email', $request->email)->first();  //通过email查找用户信息
        $remember_token = $user->remember_token;  //去user表里找remember_token
        $oauth_access_token = DB::table('oauth_access_tokens')->where('user_id', $user->id)->first();  //先用id把oauth_access_tokens表拿到数据
        $oauth_access_token_count = DB::table('oauth_access_tokens')->where('user_id', $user->id)->count();  //用id去查oauth_access_tokens表里的id
        if ($user) {
            if (Hash::check($request->password, $user->password)) {  //比对密码
                if (!$remember_token or !$oauth_access_token_count) {
                    $token = $this->getToken($request['email'], $request['password']); //获取token
                    $oauth_access_token_id = DB::table('oauth_access_tokens')
                        ->where('user_id', $user->id)
                        ->first()
                        ->id;  //把oauth_access_tokens表里的id拿到,并保存到user表的remember_id里
                    User::where('id', $user->id)
                        ->update(['remember_token' => $oauth_access_token_id]);
                    return response([
                        'message' => '登录成功',
                        'user' => $user,
                        'token' => $token
                    ], 201);
                } elseif ($remember_token === $oauth_access_token->id) {
                    //比较两个的值,如果是web用户会直接关掉浏览器,在token过期的时候,也可以登录,但是读取不了数据,401错误,授权已过期,这样的话,提示注销再重新登录就可以了
                    return response([
                        'message' => '登录成功',
                        'user' => $user
                    ], 202);
                }
            } else {
                return response([
                    'message' => '密码错误'
                ], 422);
            }
        } else {
            return response(['message' => '账号不存在'], 422);
        }
    }

    public function logout(Request $request)
    {
        if (\Auth::guard('api')->check()) {  //检测授权是否过期
            $user = \Auth::guard('api')->user();  //得到当前授权用户的信息
            User::where(['id' => $user->id])
                ->update(['remember_token' => '']);  //直接把user表里的remember_token清空
            $token = $user->token();  //获取当前用户的token,对应的表为oauth_access_tokens
            $oauth_access_token_id = $token->id;
            DB::table('oauth_refresh_tokens')
                ->where(['access_token_id' => $oauth_access_token_id])
                ->delete(); //先删除oauth_refresh_tokens表对应的数据
            $token->delete();  //然后删除oauth_access_tokens表对应的数据
            return response([
                'message' => '授权已清除 已注销'
            ], 201);
        } else {
            $user_id = $request->id; //如果授权到期,先把用户ID拿到
            $remember_token = User::find($user_id)->remember_token;
            //把三个对应的数据清空和删除掉
            DB::table('oauth_access_tokens')
                ->delete($remember_token);
            DB::table('oauth_refresh_tokens')
                ->where(['access_token_id' => $remember_token])
                ->delete();
            User::where(['id' => $user_id])
                ->update(['remember_token' => '']);
            return response([
                'message' => '授权过期 授权已清除 已注销'
            ], 401);
        }
    }

    //获取token
    public function getToken($email, $password)
    {
        $http = new Client();
        $response = $http->post(env('APP_URL') . 'oauth/token', [
            'form_params' => [
                'grant_type' => 'password',
                'client_id' => env('CLIENT_ID'),
                'client_secret' => env('CLIENT_SECRET'),
                'username' => $email,
                'password' => $password,
                'scope' => '*'
            ],
        ]);
        $this->token = json_decode((string)$response->getBody(), true);
        return $this->token;
    }
}

四、总结

屎一坨的代码。

大概意思就是这样。

如果已经一些数据。

我感觉可以这样:

去查对应user_id,revoke = 0,日期排在最后的数据,删除删除掉。

有什么好的建议,还请多多指教。

自用应该够了。

五、 补充路由,仅供参考

<?php
Route::prefix('admin')->group(function () {
    Route::post('register', 'UserController@register');
    Route::post('login', 'UserController@login');
    Route::post('logout', 'UserController@logout');
    Route::post('refresh', 'UserController@refreshToken');
});
Route::middleware('auth:api')->group(function () {
    Route::prefix('hf')->group(function () {
        Route::post('show/{id}', 'HfController@show');
        Route::post('index', 'HfController@index');
    });
});

六、PostMan测试

【大神勿进菜鸟参考】Laravel6 passport API 一个用户只有唯一 token

1. 注册

首先设置环境变量,方便调试,把token存入

【大神勿进菜鸟参考】Laravel6 passport API 一个用户只有唯一 token

在点一次登录,就不在重新获取token了,直接登录。(web用户会有这样的情况)

2. 登录

【大神勿进菜鸟参考】Laravel6 passport API 一个用户只有唯一 token

测试获取数据

【大神勿进菜鸟参考】Laravel6 passport API 一个用户只有唯一 token

3. 注销

正常退出,环境变量和ID带着

【大神勿进菜鸟参考】Laravel6 passport API 一个用户只有唯一 token

未授权或授权过期状态的退出
为了有区分,上下两个提示是不一样的。

【大神勿进菜鸟参考】Laravel6 passport API 一个用户只有唯一 token

DONE

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 1

passport 事件 处理这些 是不是更优 内部再请求 post 是否合理 ?

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!