安裝#
安裝 Passport#
1.在你的 Shell 中執(zhí)行以下命令
composerrequirelaravel/passport
如果你使用的 Laravel 版本是 5.5 以下,你需要手動(dòng)在config/app.php文件 providers 數(shù)組中加入如下代碼
Laravel\Passport\PassportServiceProvider::class,
2.運(yùn)行遷移文件
在你的 Shell 中執(zhí)行如下命令
php artisan migrate
Passport 服務(wù)提供器使用框架注冊(cè)自己的遷移目錄窍荧,因此在注冊(cè)服務(wù)后,你可以直接運(yùn)行php artisan migrate來為 Passport 生成所需的數(shù)據(jù)表
3.生成加密密鑰
在你的 Shell 中執(zhí)行如下命令
php artisan passport:install
此命令會(huì)創(chuàng)建生成安全訪問令牌時(shí)所需的加密密鑰,同時(shí)牌柄,這條命令也會(huì)創(chuàng)建用于生成訪問令牌的「?jìng)€(gè)人訪問」客戶端和「密碼授權(quán)」魄鸦。
4.添加 Trait
將 Laravel\Passport\HasApiTokens Trait 添加到 App\User 模型中
5.注冊(cè)路由
在 AuthServiceProvider 的 boot 方法中調(diào)用 Passport::routes 函數(shù)趴生。
classAuthServiceProviderextendsServiceProvider{publicfunctionboot(){$this->registerPolicies();Passport::routes();}}
如果你的程序是需要前后端分離形式的OAuth認(rèn)證而不是多平臺(tái)認(rèn)證那么你可以在routers()方法中傳遞一個(gè)匿名函數(shù)來自定定義自己需要注冊(cè)的路由,我這里是前后端分離的認(rèn)證形式氢架,因此我只需要對(duì)我的前端一個(gè)Client提供Auth的認(rèn)證,所以我只注冊(cè)了獲取Token的路由朋魔,同時(shí)我還為它自定義了前綴名岖研。
Passport::routes(function(RouteRegistrar$router){$router->forAccessTokens();},['prefix'=>'api/oauth']);
6.更改看守器驅(qū)動(dòng)
將配置文件 config/auth.php 中授權(quán)看守器 guards 的 api 的 driver 選項(xiàng)改為 passport。此調(diào)整會(huì)讓你的應(yīng)用程序在在驗(yàn)證傳入的 API 的請(qǐng)求時(shí)使用 Passport 的 TokenGuard 來處理
'guards'=>['web'=>['driver'=>'session','provider'=>'users',],'api'=>['driver'=>'passport','provider'=>'users',],],
至此 Passport 已經(jīng)安裝完成警检,剩下的文檔里所講到的前端部分的話孙援,由于我是只需要使用它做 Auth 的認(rèn)證,并不需要實(shí)現(xiàn)完整的 OAuth 功能解滓,所以我們完全可以不使用前端頁面赃磨。
使用#
為了 Api 返回?cái)?shù)據(jù)方便,我封裝了幾個(gè)函數(shù)
functionrespond($status,$respond){returnresponse()->json(['status'=>$status,is_string($respond)?'message':'data'=>$respond]);}functionsucceed($respond='Request success!'){returnrespond(true,$respond);}functionfailed($respond='Request failed!'){returnrespond(false,$respond);}
respond 函數(shù)可以做基本返回洼裤,succeed 和 failed 是在 respond 函數(shù)上做的再次封裝邻辉,用以返回請(qǐng)求成功和請(qǐng)求失敗數(shù)據(jù)。
然后我們需要使用一層代理腮鞍。
先說一下使用代理的原因值骇,Passport 認(rèn)證的流程是 從屬應(yīng)用帶著 主應(yīng)用
生成的 Client Token 和 用戶輸入的賬號(hào)密碼去請(qǐng)求主應(yīng)用的 Passport Token 路由,以獲得 access token (訪問令牌) 和 refresh token (刷新令牌)移国,然后帶著得到的 access token 就可以訪問 auth:api 下的路由了吱瘩。但是我們并沒有從屬應(yīng)用,是由前后端分離的前端來請(qǐng)求這個(gè)token迹缀,如果從前端想來拉取這個(gè) access token 就需要把 Client token 寫死在前端里使碾,這樣是很不合理的,所以我們可以在內(nèi)部寫一個(gè)代理祝懂,由應(yīng)用自身帶著 Client token 去請(qǐng)求自身以獲取 access token票摇,這樣說可能有一點(diǎn)繞,大概請(qǐng)求過程是下面這個(gè)樣子
1.前端帶著用戶輸入的賬號(hào)密碼請(qǐng)求服務(wù)端2.服務(wù)端帶著從前端接收到賬號(hào)與密碼砚蓬,并在其中添加 Client_id 與 Client_token矢门,然后帶著這些參數(shù)請(qǐng)求自身的 Passport 認(rèn)證路由,然后返回認(rèn)證后的 Access token 與 refresh token
下面是代碼實(shí)現(xiàn),我在 App\Http\Controllers\Traits 下新建了一個(gè) ProxyHelpers 的 Trait,當(dāng)然祟剔,這個(gè)函數(shù)是我根據(jù)我的業(yè)務(wù)邏輯自己封裝的隔躲,如果不適合你的業(yè)務(wù)邏輯你可以自行調(diào)整。
root().'/api/oauth/token';$params=array_merge(config('passport.proxy'),['username'=>request('email'),'password'=>request('password'),]);$respond=$client->request('POST',$url,['form_params'=>$params]);}catch(RequestException$exception){thrownewUnauthorizedException('請(qǐng)求失敗物延,服務(wù)器錯(cuò)誤');}if($respond->getStatusCode()!==401){returnjson_decode($respond->getBody()->getContents(),true);}thrownewUnauthorizedException('賬號(hào)或密碼錯(cuò)誤');}}
config/passport.php內(nèi)容如下
['grant_type'=>env('OAUTH_GRANT_TYPE'),'client_id'=>env('OAUTH_CLIENT_ID'),'client_secret'=>env('OAUTH_CLIENT_SECRET'),'scope'=>env('OAUTH_SCOPE','*'),],];
env 文件內(nèi)容如下
OAUTH_GRANT_TYPE=passwordOAUTH_CLIENT_ID=2OAUTH_CLIENT_SECRET=2HaTQJF33Sx98HjcKDiSVWZjrhVYGgkHGP8XLG1OOAUTH_SCOPE=*
我們需要用到的 client token 是 id 為 2 的 client token宣旱,不要搞錯(cuò)了喲~
然后我們只需要在控制器中 use 這個(gè) Trait,然后調(diào)用$this->authenticate()就可以得到認(rèn)證成功的 token教届,如果請(qǐng)求失敗的話响鹃,你可以使用catch來捕捉錯(cuò)誤拋出異常。
publicfunctionlogin(Request$request){$needs=$this->validate($request,rules('login'));$user=User::where('email',$needs['email'])->first();if(!$user){thrownewUnauthorizedException('此用戶不存在');}$tokens=$this->authenticate();returnsucceed(['token'=>$tokens,'user'=>newUserResource($user)]);}
得到的 tokens 返回如以下格式
{"token_type":"Bearer","expires_in":31536000,"access_token":"token_str","refresh_token":"token_str"}
做完這一切后你就可以在前端向這樣子請(qǐng)求服務(wù)端了
axios.post('yourdomain/login',login_form).then(resource=>{})
如果請(qǐng)求成功案训,那么你將會(huì)得到 用戶的信息和 access token买置,refresh token。
然后在你的前端 http 請(qǐng)求 header 里需要加入一個(gè)參數(shù)Authorization
axios.defaults.headers.common['Authorization']=token.token_type+' '+token.access_token
然后在你需要使用到 auth 認(rèn)證的路由里使用中間件auth:api强霎,一切就大功告成啦~
轉(zhuǎn)自Seaony