Laravel Oauth2認證 - Passport

Laravel Passport 基於thephpleague/oauth2-server包實現了完整的OAuth2服務php

安裝配置

  1. composer require laravel/passport
  2. 註冊Laravel\Passport\PassportServiceProvider::class
  3. 遷移passport的表
php artisan vendor:publish --tag=passport-migrations
	php artisan migrate
  1. 生成Token祕鑰php artisan passport:keys
  2. User模型增長use Laravel\Passport\HasApiTokens
  3. api guarddriver切換爲passport
  4. 註冊OAuth2路由
# AuthServiceProvider::boot中註冊令牌簽發撤銷相關的路由
		- /oauth/authorize
		- /oauth/token
	Passport::routes()
  1. 設定Token過時時間(默認不過時)
# AuthServiceProvider::boot中設置過時時間
	Passport::tokensExpireIn(Carbon::now()->addDays(15))
	Passport::refreshTokensExpireIn(Carbon::now()->addDays(30))

前端骨架

Passport提供了一套方便的JsonAPI式的Vue組件用於OAuth2相關服務前端

# 發佈vue組件至resources/assets/js/components
php artisan vendor:publish --tag=passport-components

# resources/assets/js/app.js中註冊組件
- passport-clients -> Clients.vue
- passport-authorized-clients -> AuthorizedClients.vue
- passport-personal-access-tokens -> PersonalAccessTokens.vue

# 編譯asset前端程序
npm run dev

# 使用組件服務
<passport-clients></passport-clients>
<passport-authorized-clients></passport-authorized-clients>
<passport-personal-access-tokens></passport-personal-access-tokens>

Client管理

1. Artisan方式管理vue

# 受權服務器上註冊客戶端應用
php artisan passport:client
	- 提供:應用名、受權後回調地址等
	- 響應:client ID、secret

2. JsonAPI方式管理laravel

# 認證用戶名下的客戶端列表
GET /oauth/clients

# 爲認證用戶新建客戶端
POST /oauth/clients
	- 數據:{name:'', redirect:''}
	- 響應:client ID、client secret

# 爲認證用戶更新客戶端
PUT /oauth/clients/{client-id}
	- 請求:{name:'', redirect:''}
	- 響應:client ID、client secret

# 刪除認證用戶名下的客戶端
DELETE /oauth/clients/{client-id}

受權模式

OAuth2 設計了四種受權模式用於不一樣的應用場景 受權模式選擇web

1. 受權碼 - 受權模式

  • 經過受權碼的跳轉工做流來簽發Token
  • 普遍用於用戶對第三方應用的引導受權
# 客戶端應用引導用戶至受權服務器
客戶端:Get /redirect
受權服務器:Get /oauth/authorize?client_id=&redirect_uri=http://example.com/callback&response_type=code&scope=

# 用戶贊成受權後回跳至redirect_uri
- redirect_uri必須和client註冊時的redirect一致
- 定製受權頁面
	- php artisan vendor:publish --tag=passport-views
	- 視圖路徑 resources/views/vendor/passport

# 受權碼交換token
- 客戶端:Get /callback(即redirect_uri)
- 受權服務器:Post /oauth/token
	- 數據:{grant_type:'authorization_code', client_id:'', client_secret:'', redirect_uri:'http://example.com/callback', code:''}
	- 響應:access_token、refresh_token、expires_in

# 刷新Token
受權服務器: Post /oauth/token
	- 數據:{grant_type:'refresh_token', refresh_token:'', client_id:'', client_secret:'', scope:''}
	- 響應:access_token、refresh_token、expires_in

2. 密碼 - 受權模式

  • 不用像第三方客戶端應用那樣經過受權碼跳轉
  • 方便於用戶(數據屬主)直接經過帳號密碼來交換Token

建立密碼受權客戶端npm

php artisan passport:client --password

請求Tokenjson

受權服務器:Post /oauth/token
	- 數據:{grant_type:'password', client_id:'', client_secret:'', username:'', password: '', scope: ''} #密碼受權模式能夠指定scope爲*所有權限域
	- 響應:access_token、refresh_token、expires_in

3. 簡化 - 受權模式

  • 相似於受權碼受權模式,可是簡化掉了受權碼交換的操做
  • 經常使用於JS應用、手機應用等客戶端憑據不能安全存儲的場景
# AuthServiceProvider::boot中啓用簡化受權
Passport::enableImplicitGrant()

客戶端:Get /redirect
受權服務器:/oauth/authorize?client_id=&redirect_uri=http://example.com/callback&response_type=token&scope=

4. 客戶端憑據 - 受權模式

  • 經常使用於直接面向內部應用的受權(沒有用戶參與)
受權服務器:Post /oauth/token
	- 數據:{grant_type:'client_credentials', client_id:'', client_secret:'', scope: ''} #密碼受權模式能夠指定scope爲*所有權限域
	- 響應:access_token、refresh_token、expires_in

私人訪問Token

  • 該場景不屬於OAuth2受權模式
  • 用戶自我簽發私人訪問Token便於API測試
  • Token老是有效的, 不隨過時配置而變化
# 建立私人訪問客戶端
php artisan passport:client --personal

# 管理私人訪問Token
$scopes = []
$token = $user->createToken('token_name' [, $scopes])->accessToken

## JsonAPI管理 ##
GET /oauth/scopes  #全部權限域列表
GET /oauth/personal-access-tokens  #用戶建立的全部私人訪問Token
POST /oauth/personal-access-tokens {name:'token_name', scopes:[]}  #新建私人訪問令牌
DELETE /oauth/personal-access-tokens/{token-id}  #刪除私人訪問令牌

模擬用戶+Scope

# 主要用於測試,當前用戶模擬爲指定用戶
Passport::actingAs($user, array scopes)

Artisan快捷方式

# 快捷生成三個組件:
	 - token祕鑰
	 - 密碼受權客戶端
	 - personal access client
php artisan passport:install

路由保護

  • ->middleware('auth:api') (配置api guard使用passport driver
  • 客戶端請求需帶上頭部
    • Accept: application/json
    • Authorization: Bearer Token

Token Scopes

定義Scope - 表明了一個權限組api

# AuthServiceProvider::boot中定義
Passport::tokensCan([
    '權限名' => '權限描述',
    ...
]);

Token設定Scope安全

- 受權碼模式
	客戶端:Get /redirect
	受權服務器:Get /oauth/authorize?client_id=&redirect_uri=http://example.com/callback&response_type=code&scope=權限列表(空格隔開)
- 私人令牌模式
	$scopes = []
	$token = $user->createToken('token_name' [, $scopes])->accessToken

檢查Scope服務器

# `\App\Http\Kernel::$routeMiddleware`註冊如下路由中間件
- 'scopes' => \Laravel\Passport\Http\Middleware\CheckScopes::class
	* 檢查知足全部權限域
	* `->middleware('scopes:權限域1,...')`
- 'scope' => \Laravel\Passport\Http\Middleware\CheckForAnyScope::class
	* 檢查知足任一權限域
	* `->middleware('scope:權限域1,...')`

# 直接檢查用戶Token是否擁有指定權限域
$user->tokenCan('權限域')

JS訪問API

  • web中間件增長\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class
    • 自動在響應上設置一個laravel_token cookie(內含一個加密的JWT
    • 不用再顯式配置HTPP頭部的Token
  • 根據JS框架實際狀況配置請求自動帶上頭部
    • X-CSRF-TOKENCSRF Token
    • X-Requested-WithXMLHttpRequest

Token簽發事件

  • Laravel\Passport\Events\AccessTokenCreated
  • Laravel\Passport\Events\RefreshTokenCreated

注意點

  • 憑據Credential和令牌Token的區別理解(分別是獨立存儲,Credential處理client_id/secret)
相關文章
相關標籤/搜索