首先根據文件先安裝好這個
passport
包
使用Composer
包管理器安裝
composer require laravel/passport =================================== { "name": "laravel/laravel", "description": "The Laravel Framework.", "keywords": ["framework", "laravel"], "license": "MIT", "type": "project", "require": { "php": ">=5.6.4", "laravel/framework": "5.3.*", "barryvdh/laravel-ide-helper": "^2.2", "laravel/passport": "^1.0" },
在配置檔案config/app.php的providers陣列中註冊Passport服務提供者
'providers' => [ Laravel\Passport\PassportServiceProvider::class, ],
Passport服務提供著為框架註冊了自己的資料庫遷移目錄,所以在註冊之後需要遷移資料庫,Passport遷移將會為應用生成用於存放客戶端和訪問令牌的資料表:
# 在vendor/laravel/passport/database/migrations/目錄下會有五個檔案 2016_06_01_000001_create_oauth_auth_codes_table.php 2016_06_01_000001_create_oauth_auth_access_tokens_table.php 2016_06_01_000001_create_oauth_auth_refresh_tokens_table.php 2016_06_01_000001_create_oauth_auth_clients_table.php 2016_06_01_000001_create_oauth_auth_personal_access_clients_table.php
執行 php artisan migrate遷移資料表 資料庫會生成五張表
執行php artisan passport:install
[root@bogon shop]# php artisan passport:install Encryption keys generated successfully. Personal access client created successfully. Client ID: 1 Client Secret: tOcvJtXKhYSSQCNCac88XNzaQaeB2jrakiQwnurn Password grant client created successfully. Client ID: 2 Client Secret: Hxa47zrBhmXksaEBTKpGyhi1dNTVWPwCFY8jwFkQ
該命令會在storage目錄中生成認證需要的加密鍵
oauth-private.key oauth-public.key
同時會建立 'personal access' 和 'password grant' 客戶端用於生成訪問令牌,存在
oauth_clients
表中
執行完這個命令後,新增Laravel\Passport\HasApiToken sttait
到App\User
模型
namespace App; use Laravel\Passport\HasApiTokens; use Illuminate\Notifications\Notifiable; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { use HasApiTokens, Notifiable;
該trait關聯了認證相關的一些模型,可以用獲取認證過的客戶端,使用者的
token
等接下來,你需要在
app/Providers/AuthServiceProvider
的boot
方法中呼叫Passport::routes
方法,該方法將會註冊釋出/撤銷訪問令牌、客戶端以及私人訪問令牌所必需的路由
namespace App\Providers; use Laravel\Passport\Passport; use Illuminate\Support\Facades\Gate; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider { public function boot() { $this->registerPolicies(); Passport::routes(); // }
最後,在配置檔案
config/auth.php
中,需要設定api
認證guard
的driver
選項為passport
。這將告知應用在認證輸入的API請求時使用Passport
的TokenGuard
:
'api' => [ //'driver' => 'token', 'driver' => 'passport', 'provider' => 'users', ],
安裝官方文件,就對passport的配置已經完成。接下來就是在自己的專案中如何應用密碼授權模式。
首先,需要建立一個密碼發放客戶端,在配置中,已經通過執行
php artisan passport:install
命令,建立了一個密碼令牌的客戶端
客戶端請求令牌
將建立完的密碼給客戶端,然後客戶端可以通過傳送POST請求到/oauth/token路由(帶上使用者郵箱地址和密碼引數)獲取訪問令牌。
路由在AuthServiceProvider.php中通過Passport::routes方法,呼叫了安裝的passport包中的Passport類中的routes方法,
開啟檔案\Laravel\Passport\Passport 的routes 方法
public static function routes($callback = null, array $options = [])
{
$callback = $callback ?: function ($router) {
$router->all();
};
#點選all方法跳轉到\Laravel\Passport\RouteRegistrar的all方法
public function all()
{
$this->forAuthorization();
$this->forAccessTokens();
$this->forTransientTokens();
$this->forClients();
$this->forPersonalAccessTokens();
}
#走的是第二個方法點選跳到\Laravel\Passport\RouteRegistrar的forAccessTokens方法
public function forAccessTokens()
{
$this->router->post('/oauth/token', [
'uses' => 'AccessTokenController@issueToken',
'middleware' => 'throttle'
]);
$this->router->group(['middleware' => ['web', 'auth']], function ($router) {
$router->get('/oauth/tokens', [
'uses' => 'AuthorizedAccessTokenController@forUser',
]);
$router->delete('/oauth/tokens/{token_id}', [
'uses' => 'AuthorizedAccessTokenController@destroy',
]);
});
}
#看上面的post方法找到對應的控制器
\Laravel\Passport\Http\Controller\AccessTokenController > issueToken方法
public function issueToken(ServerRequestInterface $request)
{
return $this->withErrorHandling(function () use ($request) {
return $this->server->respondToAccessTokenRequest($request, new Psr7Response);
});
}
#繼續跟進程式碼,找到處理請求引數的邏輯
#進入到\Legaue\OAuth2\Server\AuthorizationServer > respondToAccessTokenRequest方法
public function respondToAccessTokenRequest(ServerRequestInterface $request, ResponseInterface $response)
{
foreach ($this->enabledGrantTypes as $grantType) {
if ($grantType->canRespondToAccessTokenRequest($request)) {
$tokenResponse = $grantType->respondToAccessTokenRequest(
$request,
$this->getResponseType(),
$this->grantTypeAccessTokenTTL[$grantType->getIdentifier()]
);
if ($tokenResponse instanceof ResponseTypeInterface) {
return $tokenResponse->generateHttpResponse($response);
}
}
}
可以列印出來$this->enabledGrantTypes,裡面有五個值,對應不同的認證方式我們使用的是密碼模式對應的就是PasswordGrant.php檔案
public function respondToAccessTokenRequest(
ServerRequestInterface $request,
ResponseTypeInterface $responseType,
\DateInterval $accessTokenTTL
) {
// Validate request
$client = $this->validateClient($request);
$scopes = $this->validateScopes($this->getRequestParameter('scope', $request));
$user = $this->validateUser($request, $client);
// Finalize the requested scopes
$scopes = $this->scopeRepository->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getIdentifier());
// Issue and persist new tokens
$accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getIdentifier(), $scopes);
$refreshToken = $this->issueRefreshToken($accessToken);
// Inject tokens into response
$responseType->setAccessToken($accessToken);
$responseType->setRefreshToken($refreshToken);
return $responseType;
}
#這個方法中首先通過validateClient方法,檢驗客戶端,獲取請求頭中的clientId和clientSecret,通過clientId查表oauth_clients,如果存在,則將id和表中的客戶端名字以及redirect路徑傳到Client類中並例項化得到物件複製給$client。然後呼叫validateUser方法校驗請求的使用者是否存在。檢視ValidateUser方法
protected function validateUser(ServerRequestInterface $request, ClientEntityInterface $client)
{
$username = $this->getRequestParameter('username', $request);
if (is_null($username)) {
throw OAuthServerException::invalidRequest('username');
}
$password = $this->getRequestParameter('password', $request);
if (is_null($password)) {
throw OAuthServerException::invalidRequest('password');
}
$user = $this->userRepository->getUserEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client
);
#開啟\Laravel\Passport\Birdge\UserRepository的getUserEntityByUserCredentials方法
public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
{
if (is_null($model = config('auth.providers.users.model'))) {
throw new RuntimeException('Unable to determine user model from configuration.');
}
if (method_exists($model, 'findForPassport')) {
$user = (new $model)->findForPassport($username);
} else {
$user = (new $model)->where('email', $username)->first();
}
if (! $user ) {
return;
} elseif (method_exists($user, 'validateForPassportPasswordGrant')) {
if (! $user->validateForPassportPasswordGrant($password)) {
return;
}
} elseif (! $this->hasher->check($password, $user->password)) {
return;
}
return new User($user->getAuthIdentifier());
}
這裡是來檢測是App\User模型來效驗使用者名稱和密碼
然後就可以使用postman來做一個簡單的請求測試
請求引數
username users表的username 預設是email欄位
password users表的password
grant_type 型別是password
client_id 資料庫生成的id
client_secret 資料庫id對應的secret
本作品採用《CC 協議》,轉載必須註明作者和本文連結