PHP的OAuth2服務器庫
將OAuth2.0干凈地安裝到您的PHP應用程序中。 從GitHub 下載代碼開始。
要求
這個庫需要PHP 5.3.9+。然而,有一個穩定的版本和開發分支的PHP 5.2.x-5.3.8為好。
安裝
這個庫遵循zend PSR-0標准。有一些自動加載器可以自動加載這個庫,但是如果你不使用它,你可以注冊OAuth2\Autoloader
:
require_once('/path/to/oauth2-server-php/src/OAuth2/Autoloader.php'); OAuth2\Autoloader::register();
使用Composer?執行以下命令:
composer.phar require bshaffer/oauth2-server-php "^1.10"
這會將需求添加到composer.json並安裝庫。
強烈建議您查看
v1.10.0
標簽以確保您的應用程序不會因為向后兼容性問題而中斷。但是,如果您想保持開發的最前沿,您可以將其設置為dev-master
。
開始使用這個庫
看菜譜的例子是最好的入門方法。對於那些僅僅瀏覽代碼示例文檔的人來說,下面是一個簡單的OAuth2服務器實現的例子:
$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password)); $server = new OAuth2\Server($storage); $server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage)); // or any grant type you like! $server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
有關這個庫如何工作的更多信息,請參閱主要概念。
學習OAuth2.0標准
-
此外,花點時間點擊OAuth2演示應用程序, 並查看使用各種授權類型的示例 的源代碼。
-
最后,請查閱OAuth2.0官方文檔,了解不合理的技術規范。
主要概念
要更好地了解OAuth規范,請參閱 學習OAuth標准。
圖書館涉及幾個主要概念:
Grant Types
授予類型允許您展示客戶端接收令牌的多種方式。
Controllers
OAuth服務器有3個端點,每個端點都可以由控制器進行配置。每個端點都在OAuth進程中執行不同的功能。
- 授權端點 - 用戶在這里由客戶端重定向來授權請求
- 令牌端點 - 客戶端向該端點發出請求以獲得訪問令牌
- 資源端點 - 客戶端請求資源,為認證令牌提供訪問令牌。該庫支持許多不同的授權類型,包括由官方OAuth規范定義的所有授權類型。
Storage Objects
該庫使用存儲接口來允許與多個數據層進行交互。以下存儲類隨庫提供,但接口允許您自定義:
Other Concepts
授予類型
OAuth2規范中有許多支持的授權類型,並且該庫允許添加自定義授權類型。支持的授權類型如下:
授權碼
該Authorization Code
補助類型是最常見的OAuth2.0的流動。它實現3腿OAuth並涉及授予客戶一個授權碼,用戶可以交換訪問令牌的用戶。點擊現場演示查看這個授權類型的實際操作。
資源所有者密碼憑證
資源所有者的用戶名和密碼作為請求的一部分提交,並且在成功認證時發出令牌。
$ curl -u testclient:testpass "http://localhost/token.php" -d 'grant_type=password&username=someuser&password=somepassword' {"access_token":"206c80413b9a96c1312cc346b7d2517b84463edd","expires_in":3600,"token_type":"bearer","scope":null}
客戶端憑證
客戶端使用他們的憑證直接檢索訪問令牌,這允許在客戶端的控制下訪問資源
$ curl -u testclient:testpass "http://localhost/token.php" -d 'grant_type=client_credentials' {"access_token":"6f05ad622a3d32a5a81aee5d73a5826adb8cbf63","expires_in":3600,"token_type":"bearer","scope":null}
刷新令牌
如果訪問令牌已過期,客戶端可以提交刷新令牌並接收新的訪問令牌。
$ curl -u testclient:testpass "http://localhost/token.php" -d 'grant_type=refresh_token&refresh_token=c54adcfdb1d99d10be3be3b77ec32a2e402ef7e3' {"access_token":"0e9d02499fe06762ecaafb9cfbb506676631dcfd","expires_in":3600,"token_type":"bearer","scope":null}
含蓄
這與Authorization Code
上面的授權類型相似,但是從授權請求返回的授權碼而不是授權碼,令牌返回給客戶端。這對客戶端證書無法安全存儲的客戶端設備(即移動設備)最為常見。
Implicit
通過將該allow_implicit
選項設置為true來為authorize
端點使用授予類型:
$storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password)); $server = new OAuth2\Server($storage, array('allow_implicit' => true)); $server->handleAuthorizeRequest(OAuth2\Request::createFromGlobals())->send();
重要的是要注意,這不是作為
Grant Type
類添加的,因為隱式授權類型是使用authorize
端點而不是token
端點來請求的。
智威湯遜旗手
客戶端可以向令牌端點提交請求中的JWT(JSON Web令牌)。然后直接返回一個訪問令牌(沒有刷新令牌)。
延期補助金
通過實現OAuth2\GrantType\GrantTypeInterface
並將其添加到OAuth2服務器對象來創建您自己的授予類型。JWT Bearer
上面的格蘭特類型就是一個例子。
多個授權類型
如果您想要支持多個授予類型,則可以在創建服務器對象時添加更多:
$server->addGrantType(new OAuth2\GrantType\UserCredentials($storage)); $server->addGrantType(new OAuth2\GrantType\RefreshToken($storage)); $server->addGrantType(new OAuth2\GrantType\AuthorizationCode($storage));
##限制授予類型給客戶
客戶機可用grant_type
的授予類型由客戶機存儲器中的字段和授權服務器內提供的授予類型的組合來控制。
當客戶端擁有配置的授權類型列表時,客戶端僅限於使用這些授予類型。如果沒有配置授權類型,則客戶端可以使用的授權類型不受限制,它可以使用授權服務器內可用的所有授權類型。
控制器
...最終用戶(資源所有者)可以授予打印服務(客戶端)訪問存儲在照片共享服務(資源服務器)中的受保護照片,而不必與打印服務共享她的用戶名和密碼。相反,她直接使用照片共享服務(授權服務器)信任的服務器進行身份驗證,授權服務器發布打印服務委派特定憑據(訪問令牌)。
〜OAuth2(草稿#31)
大多數的OAuth2的API將有終點Authorize Requests
,Token Requests
和Resource Requests
。該OAuth2\Server
對象具有處理每個請求的方法。
下面的每個控制器通過相同的名稱對應於端點。
存儲
概觀
該庫支持多個不同存儲引擎的適配器。其中包括PDO(用於MySQL,SQLite,PostgreSQL等), MongoDB,Redis和 Cassandra。
這是通過多個PHP接口完成的,這個接口決定了如何存儲不同的對象。接口允許對多個平台進行擴展和定制,使得編寫自己的存儲類容易 。
請求和響應
請求對象
每個服務器調用都以一個請求開始。這個庫使用自己的簡單對象來驗證對服務器的調用。你幾乎總是會這樣創建:
$request = OAuth2\Request::createFromGlobals(); // call the OAuth server with it $server->handleTokenRequest($request);
因為這使用PHP接口,所以我們可以很容易地擴展它為我們正在使用的框架:
// use HttpFoundation Requests instead, for Symfony / Twig / Laravel 4 / Drupal 8 / etc! $symfony_request = Symfony\Component\HttpFoundation\Request::createFromGlobals(); $request = OAuth2\HttpFoundationBridge\Request::createFromRequest($symfony_request) // call the OAuth server with it $server->handleTokenRequest($request);
響應對象
響應對象服務於使您的服務器符合OAuth2的目的。它將為有效或無效的oauth請求設置適當的狀態碼,標題和響應正文。要使用它作為最簡單的級別,只需發送輸出並退出:
$request = OAuth2\Request::createFromGlobals(); $response = new OAuth2\Response(); // will set headers, status code, and json response appropriately for success or failure $server->grantAccessToken($request, $response); $response->send();
響應對象也可以用來自定義輸出。在下面,如果請求無效,則錯誤被發送到瀏覽器:
if (!$token = $server->grantAccessToken($request, $response)) { $response->send(); die(); } echo sprintf('Your token is %s!!', $token);
這將填充適當的錯誤標題,並返回一個JSON錯誤響應。如果您不想發送JSON響應,則可以使用響應對象以任何其他格式顯示信息:
if (!$token = $server->grantAccessToken($request, $response)) { $parameters = $response->getParameters(); // format as XML header("HTTP/1.1 " . $response->getStatusCode()); header("Content-Type: text/xml"); echo "<error><name>".$parameters['error']."</name><message>".$parameters['error_description']."</message></error>"; }
在框架或現有代碼庫中工作時,這非常有用,因為這個庫不能完全控制響應。
請參閱HttpFoundation Bridge庫,使用HttpFoundation庫將您的請求/響應插入到框架中。
范圍
配置您的范圍
在OAuth2應用程序中使用范圍通常是正確許可的關鍵。范圍用於限制資源所有者授予客戶的授權。這個最受歡迎的用途是Facebook用戶向客戶授權各種不同功能的能力(“訪問基本信息”,“貼在牆上”等)。
在這個庫中,范圍是通過實現來處理的OAuth2\Storage\ScopeInterface
。這可以使用你自己的實現,或者利用現有的OAuth2\Storage\Memory
類來完成:
// configure your available scopes $defaultScope = 'basic'; $supportedScopes = array( 'basic', 'postonwall', 'accessphonenumber' ); $memory = new OAuth2\Storage\Memory(array( 'default_scope' => $defaultScope, 'supported_scopes' => $supportedScopes )); $scopeUtil = new OAuth2\Scope($memory); $server->setScopeUtil($scopeUtil);
這是最簡單的方法,但范圍也可以動態配置:
// configure your available scopes $doctrine = Doctrine_Core::getTable('OAuth2Scope'); $scopeUtil = new OAuth2\Scope($doctrine); $server->setScopeUtil($scopeUtil);
這個例子假設正在使用的類實現OAuth2\Storage\ScopeInterface
:
class OAuth2ScopeTable extends Doctrine_Table implements OAuth2\Storage\ScopeInterface { public function getDefaultScope($client_id = null) { //... } public function scopeExists($scope, $client_id = null) { //... } }
驗證你的范圍
在服務器類中配置范圍將確保客戶端請求的范圍是有效的。但是,要確保正確驗證范圍,需要執行兩個步驟。首先,請求的范圍必須在授權的情況下暴露給資源所有者。在這個庫中,這個被實現了100%。用戶界面或必須清楚授權的范圍。其次,資源請求本身必須指定訪問它所需的范圍:
// https://api.example.com/resource-requiring-postonwall-scope $request = OAuth2\Request::createFromGlobals(); $response = new OAuth2\Response(); $scopeRequired = 'postonwall'; // this resource requires "postonwall" scope if (!$server->verifyResourceRequest($request, $response, $scopeRequired)) { // if the scope required is different from what the token allows, this will send a "401 insufficient_scope" error $response->send(); }
定制您的范圍
由於每個應用程序的“范圍”的實現可能會有很大差異,因此提供除OAuth2 \ Scope以外的其他類別可能會有所幫助。OAuth2\ScopeInterface
在自定義類中實現以完全自定義。
州
該state
參數默認為授權重定向所必需的。這相當於一個CSRF
令牌,並為您的授權請求提供會話驗證。有關 狀態的更多信息,請參閱OAuth2.0規范。
為了安全起見,這是默認啟用的,但是當你配置你的服務器時,你可以刪除這個需求:
// on creation $server = new OAuth2\Server($storage, array('enforce_state' => false)); // or after creation $server = new OAuth2\Server(); $server->setConfig('enforce_state', false);
使用多個范圍
您可以通過在授權請求中提供以空格分隔(但是網址安全)的作用域列表來請求多個作用域。它看起來像這樣:
https://mydomain.com/authorize
?client_id=MY_CLIENT
&response_type=code
&scope=onescope%20twoscope%20redscope%20bluescope
注意:額外的換行符僅用於可讀性
這將創建一個授權代碼,具有以下四個范圍:“onescope”,“twoscope”,“redscope”和“bluescope”
然后這四個范圍將根據使用OAuth2\ScopeUtil
該類的可用范圍進行驗證,以確保它們存在。如果您收到錯誤invalid_scope: An unsupported scope was requested
,這是因為您需要在服務器對象上設置可用的作用域,如下所示:
$scope = new OAuth2\Scope(array( 'supported_scopes' => array('onescope', 'twoscope', 'redscope', 'bluescope') )); $server->setScopeUtil($scope);
##將范圍限制到客戶端客戶端可用的范圍由scope
客戶端存儲器中的字段和范圍存儲器中定義的可用范圍列表的組合來控制。
當客戶端有一個配置的范圍列表時,客戶端被限制為僅使用那些范圍。當沒有配置范圍時,客戶端可以使用的范圍不受限制,它可以使用授權服務器內可用的所有范圍。
用戶ID
將本地用戶與訪問令牌相關聯
一旦你對一個用戶進行了認證並發布了一個訪問令牌(比如一個授權控制器),那么你可能想知道當訪問令牌被使用時,哪個用戶使用了一個訪問令牌。
您可以通過使用以下可選的user_id參數來執行此操作handleAuthorizeRequest
:
$userid = 1234; // A value on your server that identifies the user $server->handleAuthorizeRequest($request, $response, $is_authorized, $userid);
這將使用訪問令牌將用戶標識保存到數據庫中。當令牌被客戶端使用時,您可以檢索關聯的ID:
if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) { $server->getResponse()->send(); die; } $token = $server->getAccessTokenData(OAuth2\Request::createFromGlobals()); echo "User ID associated with this token is {$token['user_id']}";
OpenID Connect
例子
您可以在演示站點上看到運行OpenID Connect 的示例(選擇OpenID Connect
選項卡),以及 使用密鑰存儲對象的配置選項設置 的代碼。use_openid_connect
概觀
使用OpenID Connect包含兩個主要組件:
1.生成公鑰和私鑰
創建公鑰和私鑰pem
文件的細節超出了本文檔的范圍,但可以在網上找到說明 。
2.確保id_token
列存在授權碼存儲。
例如,如果使用PDO,請運行以下查詢:
ALTER TABLE oauth_authorization_codes ADD id_token VARCHAR(1000) NULL DEFAULT NULL;
3.設置use_openid_connect
和issuer
配置參數
// create storage object $storage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password)); // configure the server for OpenID Connect $config['use_openid_connect'] = true; $config['issuer'] = 'brentertainment.com'; // create the server $server = new OAuth2\Server($storage, $config);
4.創建您的密鑰存儲並將其添加到服務器:
$publicKey = file_get_contents('/path/to/pubkey.pem'); $privateKey = file_get_contents('/path/to/privkey.pem'); // create storage $keyStorage = new OAuth2\Storage\Memory(array('keys' => array( 'public_key' => $publicKey, 'private_key' => $privateKey, ))); $server->addStorage($keyStorage, 'public_key');
注意:通過創建公鑰表也可以將密鑰存儲在您的PDO數據庫中:
sqlCREATE TABLE oauth_public_keys ( client_id VARCHAR(80), public_key VARCHAR(2000), private_key VARCHAR(2000), encryption_algorithm VARCHAR(100) DEFAULT 'RS256' )
驗證OpenID Connect
如果您的服務器正確配置了OpenID Connect,則當您請求訪問令牌並將其openid
作為請求的作用域之一包含時,訪問令牌響應將包含一個id_token
。
// create a request object to mimic an authorization code request $request = new OAuth2\Request(array( 'client_id' => 'SOME_CLIENT_ID', 'redirect_uri' => 'http://brentertainment.com', 'response_type' => 'code', 'scope' => 'openid', 'state' => 'xyz', )); $response = new OAuth2\Response(); $server->handleAuthorizeRequest($request, $response, true); // parse the returned URL to get the authorization code $parts = parse_url($response->getHttpHeader('Location')); parse_str($parts['query'], $query); // pull the code from storage and verify an "id_token" was added $code = $server->getStorage('authorization_code') ->getAuthorizationCode($query['code']); var_export($code);
如果您的應用程序正確配置為OpenID,則您的輸出應如下所示:
array ( 'code' => '3288362b828be2cf9eb2327bb30773a45c3fc151', 'client_id' => 'SOME_CLIENT_ID', 'user_id' => NULL, 'redirect_uri' => 'http://brentertainment.com', 'expires' => 1442944611, 'scope' => 'openid', 'id_token' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvY XV0aDItc2VydmVyLWJ1bmRsZSIsInN1YiI6bnVsbCwiYXVkIjoidGVzdC1jbGllbn QtNTM4MDM0ODkyIiwiaWF0IjoxNDQyOTQ0NTgxLCJleHAiOjE0NDI5NDgxODEsImF 1dGhfdGltZSI6MTQ0Mjk0NDU4MX0.Ev-vPTeL1CxmSRpvV0l1nyeogpeKO2uQDuVt YbVCphfA8sLBWAVFixnCqsZ2BSLf30KzDCSzQCvSh8jgKOTQAsznE69ODSXurj3NZ 0IBufgOfLjGi0E4JvI_KksAVewy53mcN2DBSRmtJjwZ8BKjzQnOIJ77LGpQKvpW4S kmZE4', )
該物業"id_token"
表明OpenID Connect正在運行。如果遇到問題,請確保SOME_CLIENT_ID
使用有效的客戶端ID進行替換。
智威湯遜訪問令牌
概觀
JWT訪問令牌提供了一種創建和驗證訪問令牌的方法,而不需要像數據庫這樣的中央存儲。這在驗證訪問令牌時減少了 OAuth2服務的延遲。
JWT訪問令牌使用JSON Web簽名 (第6.2章)和 公鑰加密 來確定其有效性。OAuth2.0服務器使用a標記令牌private key
,其他方可以使用服務器驗證令牌public key
。
格式
JWT訪問令牌具有以下格式:
HEADER.PAYLOAD.SIGNATURE
這HEADER
是以下JSON的Base64 URL安全編碼:
{"typ": "JWT", "alg":"RS256"}
這PAYLOAD
是一個帶有以下字段的JSON對象的Base64 URL安全編碼:
{
"id": "394a71988caa6cc30601e43f5b6569d52cd7f6df", "jti": "394a71988caa6cc30601e43f5b6569d52cd7f6df", "iss": "issuer_id", "aud": "client_id", "sub": "user_id", "exp": 1483711650, "iat": 1483708050, "token_type": "bearer", "scope": "onescope twoscope" }
id
- 令牌的內部標識jti
- 令牌的唯一令牌標識符(JWT ID)iss
- 頒發令牌的服務器的ID(頒發者)aud
- 請求令牌的客戶的身份(受眾)sub
- 令牌被釋放的用戶的標識(主題)exp
- 令牌到期時的UNIX時間戳(到期)iat
- 創建令牌時的UNIX時間戳(發出時間)token_type
- 這種象征,將成為持有者scope
- 發布令牌的空間分隔的作用域列表
使用JWT訪問令牌與此庫
創建公鑰和私鑰對
要開始,你需要一個公鑰/私鑰對。這些可以使用以下命令在任何基於Unix的操作系統上生成:
# private key
$ openssl genrsa -out privkey.pem 2048
# public key
$ openssl rsa -in privkey.pem -pubout -out pubkey.pem
基本用法
配置服務器的最簡單方法是為use_jwt_access_tokens
OAuth服務器的配置提供選項:
$server = new OAuth2\Server($storage, array( 'use_jwt_access_tokens' => true, ));
這將需要您創建一個PublicKey
存儲對象。您可以使用內置Memory
存儲:
// your public key strings can be passed in however you like $publicKey = file_get_contents('/path/to/pubkey.pem'); $privateKey = file_get_contents('/path/to/privkey.pem'); // create storage $storage = new OAuth2\Storage\Memory(array('keys' => array( 'public_key' => $publicKey, 'private_key' => $privateKey, ))); $server = new OAuth2\Server($storage, array( 'use_jwt_access_tokens' => true, ));
這是使用JWT訪問令牌時的最小配置,並且將是ResourceController
唯一有效的。對於完整的服務器配置,您必須提供Client
存儲和一些授權類型。
以下是完整的服務器配置示例:
// token.php // error reporting (this is a demo, after all!) ini_set('display_errors',1);error_reporting(E_ALL); // Autoloading (composer is preferred, but for this example let's just do this) require_once('oauth2-server-php/src/OAuth2/Autoloader.php'); OAuth2\Autoloader::register(); // your public key strings can be passed in however you like // (there is a public/private key pair for testing already in the oauth library) $publicKey = file_get_contents('oauth2-server-php/test/config/keys/id_rsa.pub'); $privateKey = file_get_contents('oauth2-server-php/test/config/keys/id_rsa'); // create storage $storage = new OAuth2\Storage\Memory(array( 'keys' => array( 'public_key' => $publicKey, 'private_key' => $privateKey, ), // add a Client ID for testing 'client_credentials' => array( 'CLIENT_ID' => array('client_secret' => 'CLIENT_SECRET') ), )); $server = new OAuth2\Server($storage, array( 'use_jwt_access_tokens' => true, )); $server->addGrantType(new OAuth2\GrantType\ClientCredentials($storage)); // minimum config // send the response $server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
現在您可以調用您的服務器並接收JWT訪問令牌:
# start the PHP built-in web server
$ php -S localhost:3000 &
$ curl -i -v http://localhost:3000/token.php -u 'CLIENT_ID:CLIENT_SECRET' -d "grant_type=client_credentials"
服務器將返回一個包含JWT訪問令牌的響應:
{
"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpZCI6IjYzMjIwNzg0YzUzODA3ZjVmZTc2Yjg4ZjZkNjdlMmExZTIxODlhZTEiLCJjbGllbnRfaWQiOiJUZXN0IENsaWVudCBJRCIsInVzZXJfaWQiOm51bGwsImV4cGlyZXMiOjEzODAwNDQ1NDIsInRva2VuX3R5cGUiOiJiZWFyZXIiLCJzY29wZSI6bnVsbH0.PcC4k8Q_etpU-J4yGFEuBUdeyMJhtpZFkVQ__sXpe78eSi7xTniqOOtgfWa62Y4sj5Npta8xPuDglH8Fueh_APZX4wGCiRE1P4nT4APQCOTbgcuCNXwjmP8znk9F76ID2WxThaMbmpsTTEkuyyUYQKCCdxlIcSbVvcLZUGKZ6-g", "client_id":"CLIENT_ID", "user_id":null, "expires":1382630473, "scope":null }
資源服務器配置
如果您的資源服務器與您的授權服務器分開,則可以在沒有授權服務器的私鑰的情況下配置您的服務器:
/* for a Resource Server (minimum config) */ $publicKey = file_get_contents('/path/to/pubkey.pem'); // no private key necessary $keyStorage = new OAuth2\Storage\Memory(array('keys' => array( 'public_key' => $publicKey, ))); $server = new OAuth2\Server($keyStorage, array( 'use_jwt_access_tokens' => true, ));
這允許您的服務器驗證訪問令牌,而不向Authorization Server或任何其他共享資源發出任何請求。
// verify the JWT Access Token in the request if (!$server->verifyResourceRequest(OAuth2\Request::createFromGlobals())) { exit("Failed"); } echo "Success!";
現在你可以請求這個,並嘗試發送上面生成的令牌!
# start the PHP built-in web server
$ php -S localhost:3000 &
$ curl "http://localhost:3000/resource.php?access_token=eyJ0eXAi..."
Success!
使用輔助存儲
該庫允許您將訪問令牌備份到輔助存儲。只是通過實施一個對象OAuth2\Storage\AccessTokenInterface
到JwtAccessToken
對象到具有存儲在一個附加的位置的訪問令牌:
$pdoStorage = new OAuth2\Storage\Pdo($pdo); // access token will also be saved to PDO $keyStorage = new OAuth2\Storage\Memory(array('keys' => array( 'public_key' => $publicKey, 'private_key' => $privateKey, )));
此示例從Memory
存儲中提取公鑰/私鑰,並Pdo
在簽名后將授予的訪問令牌保存到存儲。
特定於客戶端的加密密鑰
制作特定於客戶端的密鑰是一個好主意。這樣,如果密鑰對受到攻擊,只有一個客戶端受到影響。雙方Memory
並Pdo
支持這種類型的存儲。這里是一個使用Memory
存儲的例子:
$keyStorage = new OAuth2\Storage\Memory(array('keys' => array( 'ClientID_One' => array( 'public_key' => file_get_contents('/path/to/client_1_rsa.pub'), 'private_key' => file_get_contents('/path/to/client_1_rsa'), ), 'ClientID_Two' => array( 'public_key' => file_get_contents('/path/to/client_2_rsa.pub'), 'private_key' => file_get_contents('/path/to/client_2_rsa'), ), // declare global keys as well 'public_key' => file_get_contents('/path/to/global_rsa.pub'), 'private_key' => file_get_contents('/path/to/global_rsa'), )));
對於Pdo
,運行以下查詢:
/* create the database table */ CREATE TABLE oauth_public_keys (client_id VARCHAR(80), public_key VARCHAR(8000), private_key VARCHAR(8000), encryption_algorithm VARCHAR(80) DEFAULT "RS256")
使用這樣的插入樣本數據:
/* insert global keys into the database */ INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES (NULL, "...", "...", "RS256"); /* add client-specific key pairs */ INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES ("ClientID_One", "...", "...", "RS256"); INSERT INTO oauth_public_keys (client_id, public_key, private_key, encryption_algorithm) VALUES ("ClientID_Two", "...", "...", "RS256");
並實例化PDO存儲對象:
$dsn = 'mysql:dbname=my_oauth2_db;host=localhost'; $username = 'root'; $password = ''; $pdoStorage = new OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
配置不同的算法
JwtAccessTokens支持以下算法:
- “HS256” - 使用
hash_hmac
/ sha256 - “HS384” - 使用
hash_hmac
/ sha384 - “HS512” - 使用
hash_hmac
/ sha512 - “RS256” - 使用
openssl_sign
/ sha256 - “RS384” - 使用
openssl_sign
/ sha384 - “RS512” - 使用
openssl_sign
/ sha512
在你的OAuth2\Storage\PublicKeyInterface
實例中進行配置。當使用Memory
存儲時,這看起來像這樣:
$storage = new OAuth2\Storage\Memory(array('keys' => array( 'public_key' => $publicKey, 'private_key' => $privateKey, 'encryption_algorithm' => 'HS256', // "RS256" is the default )));
客戶端驗證
簽名可以用任何編程語言進行驗證。使用標准的 Public Key
加密方法來驗證訪問令牌簽名。這是在PHP中的一個例子:
$token = json_decode($curlResponse); $jwt_access_token = $token['access_token']; $separator = '.'; if (2 !== substr_count($jwt_access_token, $separator)) { throw new Exception("Incorrect access token format"); } list($header, $payload, $signature) = explode($separator, $jwt_access_token); $decoded_signature = base64_decode(str_replace(array('-', '_'), array('+', '/'), $signature)); // The header and payload are signed together $payload_to_verify = utf8_decode($header . $separator . $payload); // however you want to load your public key $public_key = file_get_contents('/path/to/pubkey.pem'); // default is SHA256 $verified = openssl_verify($payload_to_verify, $decoded_signature, $public_key, OPENSSL_ALGO_SHA256); if ($verified !== 1) { throw new Exception("Cannot verify signature"); } // output the JWT Access Token payload var_dump(base64_decode($payload));