Laravel Passport API 認證使用小結
看到Laravel-China 社區常有人問 Laravel Passport 用於密碼驗證方式來獲取 Token 的問題,剛好我最近一個 API 項目使用 Laravel Dingo Api
+Passport
,也是使用 Oauth2 的'grant_type' => 'password'
密碼授權來做 Auth 驗證,對於如何做登錄登出,以及多賬號系統的認證等常用場景做一下簡單的使用小總結。
基本配置
基本安裝配置主要參照官方文檔,具體不詳細說,列出關鍵代碼段
config/auth.php
'guards' => [ 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => \App\Models\User::class ], ],
Providers/AuthServiceProvider.php
public function boot() { $this->registerPolicies(); //默認令牌發放的有效期是永久 //Passport::tokensExpireIn(Carbon::now()->addDays(2)); //Passport::refreshTokensExpireIn(Carbon::now()->addDays(4)); Passport::routes(function (RouteRegistrar $router) { //對於密碼授權的方式只要這幾個路由就可以了 config(['auth.guards.api.provider' => 'users']); $router->forAccessTokens(); }); }
Middleware/AuthenticateApi.php 自定義中間件返回
App/Http/Kernel.php
/** * The application's route middleware. * * These middleware may be assigned to groups or used individually. * * @var array */ protected $routeMiddleware = [ 'api-auth' => AuthenticateApi::class, ...... ]; }
賬號驗證字段不止郵箱
對於賬號驗證不止是數據表中的 emial 字段,還可能是用戶名或者手機號字段只需要在 User 模型中添加findForPassport
方法,示例代碼如下:
App\Models\Users
class User extends Authenticatable implements Transformable { use TransformableTrait, HasApiTokens, SoftDeletes; public function findForPassport($login) { return $this->orWhere('email', $login)->orWhere('phone', $login)->first(); } }
客戶端獲取 access_token 請求只傳用戶名和密碼
對於密碼授權的方式需要提交的參數如下:
$response = $http->post('http://your-app.com/oauth/token', [ 'form_params' => [ 'grant_type' => 'password', 'client_id' => 'client-id', 'client_secret' => 'client-secret', 'username' => 'taylor@laravel.com', 'password' => 'my-password', 'scope' => '', ], ]);
但是客戶端請求的時候不想把grant_type
,client_id
,client_secret
,scope
放到請求參數中或者暴露給客戶端,只像 JWT 一樣只發送username
和password
怎么辦?很簡單我們只要將不需要請求的放到配置文件中,然后客戶端請求用戶名密碼以后我們再向oauth/token
發送請求帶上相關的配置就可以了。
.env.php
OAUTH_GRANT_TYPE=password OAUTH_CLIENT_ID=1 OAUTH_CLIENT_SECRET=EvE4UPGc25TjXwv9Lmk432lpp7Uzb8G4fNJsyJ83 OAUTH_SCOPE=*
config/passport.php 當然該配置你可以配置多個client
return [ 'grant_type' => env('OAUTH_GRANT_TYPE'), 'client_id' => env('OAUTH_CLIENT_ID'), 'client_secret' => env('OAUTH_CLIENT_SECRET'), 'scope' => env('OAUTH_SCOPE', '*'), ];
LoginController.php的示例代碼如下,因為用了Dingo Api
配置了api
前綴,所以請求/api/oauth/token
/** * 獲取登錄TOKEN * @param LoginRequest $request * @return \Illuminate\Http\JsonResponse */ public function token(LoginRequest $request) { $username = $request->get('username'); $user = User::orWhere('email', $username)->orWhere('phone', $username)->first(); if ($user && ($user->status == 0)) { throw new UnauthorizedHttpException('', '賬號已被禁用'); } $client = new Client(); try { $request = $client->request('POST', request()->root() . '/api/oauth/token', [ 'form_params' => config('passport') + $request->only(array_keys($request->rules())) ]); } catch (RequestException $e) { throw new UnauthorizedHttpException('', '賬號驗證失敗'); } if ($request->getStatusCode() == 401) { throw new UnauthorizedHttpException('', '賬號驗證失敗'); } return response()->json($request->getBody()->getContents()); }
退出登錄並清除 Token
對於客戶端退出后並清除記錄在oauth_access_tokens
表中的記錄,示例代碼如下:
/** * 退出登錄 */ public function logout() { if (\Auth::guard('api')->check()) { \Auth::guard('api')->user()->token()->delete(); } return response()->json(['message' => '登出成功', 'status_code' => 200, 'data' => null]); }
根據用戶 ID 認證用戶
app('auth')->guard('api')->setUser(User::find($userId));
多用戶表(多 Auth)認證
比如針對客戶表和管理員表分別做 Auth 認證的情況,也列出關鍵代碼段:
'guards' => [ 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], 'admin_api' => [ 'driver' => 'passport', 'provider' => 'admin_users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => \App\Models\User::class ], 'admin_users' => [ 'driver' => 'eloquent', 'model' => \App\Models\AdminUser::class ], ],
新建一個PasspordAdminServiceProvider來實現我們自己的PasswordGrant
,別忘了添加到config/app.php
的providers
配置段中
AppProviders/PasspordAdminServiceProvider
新建AdminUserPassportRepository,Password 的驗證主要通過getUserEntityByUserCredentials
,它讀取配置的guards
對應的provider
來做認證,我們重寫該方法,通過傳遞一個參數來告訴它我們要用哪個guard
來做客戶端認證
登錄和單用戶系統一樣,只是在請求oauth/token
的時候帶上guard
參數,示例代碼如下:
Admin/Controllers/Auth/LoginController.php
轉載請注明: 轉載自Ryan 是菜鳥 | LNMP 技術棧筆記