前言
最近在寫(xiě)一個(gè)前后端分離項(xiàng)目,本來(lái)想用 Jwt-auth + Dingo 開(kāi)發(fā)的,但是略感笨重,于是想到了 Laravel 的 Passport 和 5.5 新出的 Api Resource。Laravel Passport 是一套已經(jīng)封裝好的 OAuth2 服務(wù)端實(shí)現(xiàn)
OAuth是一個(gè)關(guān)于授權(quán)(authorization)的開(kāi)放網(wǎng)絡(luò)標(biāo)準(zhǔn),在全世界得到廣泛應(yīng)用,目前的版本是2.0版。
OAuth 2.0 是目前比較流行的做法,它率先被Google, Yahoo, Microsoft, Facebook等使用。之所以標(biāo)注為 2.0,是因?yàn)樽畛跤幸粋€(gè)1.0協(xié)議,但這個(gè)1.0協(xié)議被弄得太復(fù)雜,易用性差,所以沒(méi)有得到普及。2.0是一個(gè)新的設(shè)計(jì),協(xié)議簡(jiǎn)單清晰,但它并不兼容1.0,可以說(shuō)與1.0沒(méi)什么關(guān)系。
所以這里就不細(xì)說(shuō)了,先來(lái)看看怎么安裝它吧。
安裝
安裝 Passport
1.在你的 Shell 中執(zhí)行以下命令
composer require laravel/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 來(lái)為 Passport 生成所需的數(shù)據(jù)表
3.生成加密密鑰
在你的 Shell 中執(zhí)行如下命令
php artisan passport:install
此命令會(huì)創(chuàng)建生成安全訪問(wèn)令牌時(shí)所需的加密密鑰,同時(shí),這條命令也會(huì)創(chuàng)建用于生成訪問(wèn)令牌的「?jìng)€(gè)人訪問(wèn)」客戶端和「密碼授權(quán)」。
4.添加 Trait
將 LaravelPassportHasApiTokens Trait 添加到 AppUser 模型中
<?php namespace App; use Laravel\Passport\HasApiTokens; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use HasApiTokens, Notifiable; }
5.注冊(cè)路由
在 AuthServiceProvider 的 boot 方法中調(diào)用 Passport::routes
函數(shù)。
class AuthServiceProvider extends ServiceProvider { public function boot() { $this->registerPolicies(); Passport::routes(); } }
如果你的程序是需要前后端分離形式的OAuth認(rèn)證而不是多平臺(tái)認(rèn)證那么你可以在routers()方法中傳遞一個(gè)匿名函數(shù)來(lái)自定定義自己需要注冊(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 來(lái)處理
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'passport', 'provider' => 'users', ], ],
至此 Passport 已經(jīng)安裝完成,剩下的文檔里所講到的前端部分的話,由于我是只需要使用它做 Auth 的認(rèn)證,并不需要實(shí)現(xiàn)完整的 OAuth 功能,所以我們完全可以不使用前端頁(yè)面。
使用
為了 Api 返回?cái)?shù)據(jù)方便,我封裝了幾個(gè)函數(shù)
function respond($status, $respond) { return response()->json(['status' => $status, is_string($respond) ? 'message' : 'data' => $respond]); } function succeed($respond = 'Request success!') { return respond(true, $respond); } function failed($respond = 'Request failed!') { return respond(false, $respond); }
respond 函數(shù)可以做基本返回,succeed 和 failed 是在 respond 函數(shù)上做的再次封裝,用以返回請(qǐng)求成功和請(qǐng)求失敗數(shù)據(jù)。
然后我們需要使用一層代理。
先說(shuō)一下使用代理的原因,Passport 認(rèn)證的流程是 從屬應(yīng)用帶著 主應(yīng)用
生成的 Client Token 和 用戶輸入的賬號(hào)密碼去請(qǐng)求主應(yīng)用的 Passport Token 路由,以獲得 access token (訪問(wèn)令牌) 和 refresh token (刷新令牌),然后帶著得到的 access token 就可以訪問(wèn) auth:api 下的路由了。但是我們并沒(méi)有從屬應(yīng)用,是由前后端分離的前端來(lái)請(qǐng)求這個(gè)token,如果從前端想來(lái)拉取這個(gè) access token 就需要把 Client token 寫(xiě)死在前端里,這樣是很不合理的,所以我們可以在內(nèi)部寫(xiě)一個(gè)代理,由應(yīng)用自身帶著 Client token 去請(qǐng)求自身以獲取 access token,這樣說(shuō)可能有一點(diǎn)繞,大概請(qǐng)求過(guò)程是下面這個(gè)樣子
1.前端帶著用戶輸入的賬號(hào)密碼請(qǐng)求服務(wù)端