和我一樣的菜鳥可以參考參考哈。
一開始用的原生的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');
});
});
首先甚至環境變數,方便除錯,把token存入
在點一次登入,就不在重新獲取token了,直接登入。(web使用者會有這樣的情況)
測試獲取資料
正常退出,環境變數和ID帶著
未授權或授權過期狀態的退出
為了有區分,上下兩個提示是不一樣的。
DONE