在上一篇文章中(OAUTH2驗證框架之入門教程)中,咱們已經講到了Oauth2驗證框架的工做原理。知道Oauth2驗證框架工做的六個步驟:php
(A)用戶打開客戶端之後,客戶端要求用戶給予受權。git
(B)用戶贊成給予客戶端受權。github
(C)客戶端使用上一步得到的受權,向認證服務器申請令牌。數據庫
(D)認證服務器對客戶端進行認證之後,確認無誤,贊成發放令牌。編程
(E)客戶端使用令牌,向資源服務器申請獲取資源。api
(F)資源服務器確認令牌無誤,贊成向客戶端開放資源。數組
那麼在具體的項目中,真正是怎麼實現的呢?針對這個問題,本文下面將重點介紹。瀏覽器
Oauth2.0是一個很通用的驗證框架,不少編程語言都對其進行了實現,包括Java、PHP、Python、NodeJS、Ruby、NET、Erlang、Go、C等。你們能夠在以下頁面,查看本身所使用語言的實現方案。安全
https://oauth.net/code/服務器
本文以PHP的實現方案爲例,來說述Oauth2在項目中的工做流程。Java、Python、NodeJS、Ruby、NET、Erlang、Go、C等語言在項目中的工做流程,你們能夠對照PHP的描述,自行融會貫通。
bshaffer/oauth2-server-php是一個庫,能夠實現符合標準的OAuth 2.0服務器。 使用它您的用戶能夠對應用程序客戶端進行身份驗證和受權,並保護您的API。
在具體講述bshaffer/oauth2-server-phpr的具體實現以前,咱們先了解一下其中涉及到的幾個重要概念:
受權模式(Grant Types):授予類型容許您展現客戶端接收令牌的多種方式。
控制器(Controllers):OAuth服務器有3個端點,每一個端點均可以由控制器進行配置。每一個端點都在OAuth進程中執行不一樣的功能。受權端點(Authorize Endpoint):用戶在這裏由客戶端重定向來受權請求。令牌端點(Token Endpoint) :客戶端向該端點發出請求以得到訪問令牌。資源端點(Resource Endpoint(s)) :客戶端請求資源,爲認證令牌提供訪問令牌。該庫支持許多不一樣的受權類型,包括官方OAuth規範定義的全部受權類型。
存儲對象(Storage Objects):該庫使用存儲接口來容許與多個數據層進行交互。PDO、Redis、Mongo、Cassandra、Doctrine Storage等存儲類隨庫提供,但接口也容許您進行自定義。
其餘概念:Response Object、Scope、User IDs、JWT Access Tokens
受權模式(Grant Types)
bshaffer/oauth2-server-php庫已經實現了OAuth 2.0受權框架RFC中定義的全部受權模式:
受權碼模式(authorization code)
簡化模式(implicit)
密碼模式(resource owner password credentials)
客戶端模式(client credentials)
控制器(Controllers)
大多數OAuth2 API將具備受權請求、令牌請求和資源請求的端點。 OAuth2 Server對象具備處理每一個請求的方法。下面的每一個控制器經過相同的名稱對應於端點:
一、受權控制器
對於受權端點,要求用戶使用受權碼(受權碼模式)或訪問令牌(簡化模式)對客戶端進行認證和重定向。它有兩個方法:
handleAuthorizeRequest
validateAuthorizeRequest
handleAuthorizeRequest()的做用是接收受權請求,返回受權響應。
validateAuthorizeRequest()的做用是接收受權請求,若是傳入請求不是有效的受權請求,則返回false。 若是請求有效,則返回檢索到的客戶端詳細信息和輸入數組。 在向用戶顯示登陸或受權表單以前,應用程序應該調用它。
二、資源控制器
對於任何須要oauth2身份驗證的資源請求(即API調用)。 控制器將驗證傳入的請求,而後容許應用程序返回受保護的資源。它有兩個方法:
verifyResourceRequest
getAccessTokenData
verifyResourceRequest()的做用是接收訪問資源的請求,根據請求判斷訪問令牌(access token)是否存在,無論請求是否合法,將返回一個布爾值(true or false)。
getAccessTokenData()的做用是講接收的請求做爲參數,若是該請求有被受權返回訪問令牌(access token),不然返回null。
三、令牌控制器
對於使用配置的受權類型的令牌端點,將訪問令牌(access token)返回給客戶端。它有兩個方法:
grantAccessToken
handleTokenRequest
grantAccessToken()的做用是接收穫取訪問令牌(access token)的請求,若是請求有效,將返回訪問令牌(access token)。
handleTokenRequest()的做用是接收穫取訪問令牌(access token)的請求,返回適當響應的響應對象
存儲對象
該庫支持多個不一樣存儲引擎的適配器。 其中包括PDO(用於MySQL,SQLite,PostgreSQL等),MongoDB,Redis和Cassandra。這是經過多個PHP接口完成的,這個接口決定了如何存儲不一樣的對象。 接口容許對多個平臺進行擴展和定製,使得編寫本身的存儲類容易。存儲接口還能夠輕鬆地將對象存儲在多個數據存儲系統中。
一、要求
這個庫須要PHP 5.3.9+。 可是,PHP 5.2.x-5.3.8也有一個穩定的發佈和開發分支。
二、下載
這個庫託管在GitHub上,若是不能使用composer工具,你們也能夠在以下頁面下載使用:
https://github.com/bshaffer/oauth2-server-php
三、安裝
這個庫遵循zend PSR-0標準。 有許多自動加載器能夠自動加載這個庫,可是若是你不使用它,你能夠手動註冊OAuth2 Autoloader,以下:
若是你可使用composer工具,能夠直接使用以下命令,這個庫將自動加載到你的項目中:
composer.phar require bshaffer/oauth2-server-php "^1.10"
前面已經講到,OAuth2 Server庫已經實現了OAuth 2.0受權框架RFC中定義的全部受權模式,包括:受權碼模式(authorization code)、簡化模式(implicit)、密碼模式(resource owner password credentials)、客戶端模式(client credentials)。下面咱們來逐一說明。
注意:咱們這裏假設咱們的受權服務器的域名爲:
https://api.mysite.com
資源服務器的域名爲:
https://myredirecturi.com
一、受權碼模式(authorization code)
受權碼模式是功能最完整、流程最嚴密的受權模式。它的特色就是經過客戶端的後臺服務器,與"服務提供商"的認證服務器進行互動。如圖:
具體實現以下:
①、建立一個OAuth2 GrantType AuthorizationCode的實例並將其添加到您的服務器,以下:
②、當用戶訪問資源服務器時,咱們將其導引到受權服務器,以下:
https://api.mysite.com/authorize?response_type=code&client_id=TestClient&redirect_uri=https://myredirecturi.com/cb
③、受權服務器驗證成功後,受權服務器將傳遞一個受權碼到資源服務器,以下:
https://myredirecturi.com/cb?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz
④、資源服務器利用接收到的受權碼(code),調用受權服務器的接口,獲取訪問令牌(access token),以下:
若是調用成功,將返回以下數據:
二、簡化模式(implicit)
簡化模式(implicit grant type)不經過第三方應用程序的服務器,直接在瀏覽器中向認證服務器申請令牌,跳過了"受權碼"這個步驟,所以得名。全部步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不須要認證。
具體實現以下:
①、在建立服務器時,只需配置服務器以容許簡化模式。以下:
這容許受權控制器直接從請求返回訪問令牌到服務器的受權端點。
②、當使用簡化模式時,訪問令牌將被受權控制器檢索。 客戶端經過在OAuth服務器的「受權」端點中設置查詢字符串參數response_type = token來指定受權類型。
當用戶訪問資源服務器時,咱們將其導引到受權服務器,以下:
https://api.mysite.com/authorize?response_type=token&client_id=TestClient&redirect_uri=https://myredirecturi.com/cb
③、受權服務器驗證成功後,受權服務器將傳遞一個訪問令牌到資源服務器,以下:
https://myredirecturi.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=bearer&expires_in=3600
三、密碼模式(resource owner password credentials)
密碼模式中,用戶向客戶端提供本身的用戶名和密碼。客戶端使用這些信息,向"服務商提供商"索要受權。
在這種模式中,用戶必須把本身的密碼給客戶端,可是客戶端不得儲存密碼。這一般用在用戶對客戶端高度信任的狀況下,好比客戶端是操做系統的一部分,或者由一個著名公司出品。而認證服務器只有在其餘受權模式沒法執行的狀況下,才能考慮使用這種模式。
具體實現以下:
①、建立一個OAuth2 GrantType UserCredentials的實例並將其添加到您的服務器
注意:用戶存儲對於每一個應用程序都是高度自定義的,因此強烈建議您使用OAuth2 Storage UserCredentialsInterface來實現本身的存儲。
②、直接發送用戶憑證來獲取訪問令牌
若是您的客戶端是公共的(默認狀況下,當客戶端沒有與此相關的祕鑰時是這樣的),則能夠省略請求中的client_secret值:
③、當響應成功時,將返回訪問令牌(access token),以下:
四、客戶端模式(client credentials)
客戶端模式指客戶端以本身的名義,而不是以用戶的名義,向"服務提供商"進行認證。嚴格地說,客戶端模式並不屬於OAuth框架所要解決的問題。在這種模式中,用戶直接向客戶端註冊,客戶端以本身的名義要求"服務提供商"提供服務,其實不存在受權問題。
具體實現以下:
①、建立一個OAuth2 GrantType ClientCredentials的實例並將其添加到您的服務器
②、配置參數
客戶端模式具備如下配置:
allow_credentials_in_request_body
除了受權HTTP頭以外,是否在POST主體中查找憑證。默認值:true
③、調用接口獲取訪問令牌(access token)
調用成功時,返回以下數據:
經過上面的介紹,你們應該基本清楚了Oauth2的使用了。下面做爲擴展內容,你們能夠選擇使用。
1、受權模式
除了上面介紹的四種模式以外,該庫仍是實現了另外兩種模式:刷新令牌模式(Refresh Token)和JWT Bearer模式。
一、刷新令牌(Refresh Token)
刷新令牌模式用於獲取額外的訪問令牌,以延長客戶端對用戶資源的受權。
具體實現以下:
①、建立一個OAuth2 GrantType RefreshToken的實例並將其添加到您的服務器
注意:
只有在使用受權碼模式或密碼模式檢索令牌時才提供刷新令牌。
若是將實現OAuth2 Storage RefreshTokenInterface的存儲提供給您的OAuth2 Server實例,則只會返回刷新令牌。
②、配置參數
刷新令牌模型具備如下配置:
always_issue_new_refresh_token
是否在成功的令牌請求時發出新的刷新令牌。默認:false
訪問令牌返回類型具備如下配置:
refresh_token_lifetime
刷新令牌到期以前的時間。默認:1209600(14天)
可是,當使用服務器的配置數組建立服務器時,能夠發送這兩個配置選項:
③、刷新令牌
使用受權碼模式或密碼模式檢索令牌:
若是執行成功,將返回以下數據:
刷新令牌能夠用來生成一個等於或小於範圍的新訪問令牌:
若是執行成功,將返回以下數據:
若是服務器配置爲同時獲取令牌和刷新令牌,那麼刷新令牌也會隨着此響應返回:
二、JWT Bearer
JWT Bearer模式用於客戶端但願接收訪問令牌而不傳輸敏感信息(如客戶端密鑰)的狀況。 這也能夠與受信任的客戶端一塊兒使用,以在沒有用戶受權的狀況下訪問用戶資源。
具體實現以下:
①、建立OAuth2 GrantType JwtBearer的實例並將其添加到您的服務器
JWT請求須要使用公鑰加密技術來簽署JWT聲明。 下面的代碼片斷提供了一個如何完成的例子。
注意:本示例使用此庫中提供的OAuth2 Encryption Jwt類。 這對於JWT身份驗證不是必需的,可是方便。
②、而後能夠調用該函數來爲請求生成負載。 編寫腳原本生成jwt並請求令牌:
執行成功,將返回以下數據:
2、受權範圍(scope)
在OAuth2應用程序中使用受權範圍(scope)一般是正確許可的關鍵。 受權範圍(scope)用於資源全部者限制對客戶的受權。 如:Facebook用戶向客戶受權各類不一樣功能的能力(「訪問基本信息」,「貼在牆上」等)。
在這個庫中,受權範圍(scope)是經過實現OAuth2 Storage ScopeInterface來處理的。 可使用您本身的實現或利用現有的OAuth2 Storage Memory類來完成:
這是最簡單的方法,但範圍也能夠動態配置:
此示例假定正在使用的類實現OAuth2 Storage ScopeInterface:
驗證受權範圍
在服務器類中配置受權範圍(scope)將確保客戶端請求的受權範圍(scope)是有效的。 可是,要確保正確驗證受權範圍(scope),須要執行兩個步驟。
首先,請求的受權範圍(scope)必須在受權的狀況下暴露給資源全部者。 在這個庫中,這個被實現了100%。 用戶界面或必須清楚受權的範圍。
其次,資源請求自己必須指定訪問它所需的受權範圍(scope)
自定義受權範圍
因爲每一個應用程序的受權範圍(scope)的實現可能會有很大差別,所以提供除OAuth2 Scope之外的其餘類別可能會有所幫助。 在自定義類中實現OAuth2 ScopeInterface以徹底自定義。
state狀態參數默認是受權重定向所必需的。 這至關於一個CSRF令牌,併爲您的受權請求提供會話驗證。 這是爲了安全目的而默認啓用的,可是當你配置你的服務器時你能夠刪除這個需求
使用多個範圍
您能夠經過在受權請求中提供以空格分隔(可是網址安全)的做用域列表來請求多個做用域。 它看起來像這樣:
這將建立一個具備如下四個範圍的受權代碼:「onescope」,「twoscope」,「redscope」和「bluescope」,而後使用OAuth2 ScopeUtil類對這些範圍進行驗證,以確保它們存在。 若是您收到錯誤invalid_scope:請求不支持的做用域,這是由於您須要在服務器對象上設置可用的做用域,以下所示:
限制客戶端訪問範圍
客戶端可用的範圍由客戶端存儲中的做用域字段和做用域存儲中定義的可用做用域列表的組合來控制。當客戶端有一個配置的範圍列表時,客戶端被限制爲僅使用那些範圍。 當沒有配置範圍時,客戶端可使用的範圍不受限制,它可使用受權服務器內可用的全部範圍。
3、User IDs
將本地用戶與訪問令牌相關聯
一旦你對一個用戶進行了認證併發布了一個訪問令牌(好比一個受權控制器),那麼你可能想知道當訪問令牌被使用時哪一個用戶被應用。您能夠經過使用handleAuthorizeRequest的可選user_id參數來執行此操做:
這將使用訪問令牌將用戶標識保存到數據庫中。 當令牌被客戶端使用時,您能夠檢索關聯的ID:
參考地址:https://bshaffer.github.io/oauth2-server-php-docs