[大神勿进菜鸟参考] 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));
}
其他的配置,按照官方的默认的来就可以。
二、大概流程思路
三、控制器部分(核心部分)
<?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测试
1. 注册
首先设置环境变量,方便调试,把token存入
在点一次登录,就不在重新获取token了,直接登录。(web用户会有这样的情况)
2. 登录
测试获取数据
3. 注销
正常退出,环境变量和ID带着
未授权或授权过期状态的退出
为了有区分,上下两个提示是不一样的。
DONE
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: