oauth2-server-php-docs 概念

 

PHP的OAuth2服務器庫

將OAuth2.0乾淨地安裝到您的PHP應用程序中。 從GitHub 下載代碼開始。php

要求

這個庫須要PHP 5.3.9+然而,有一個穩定的版本開發分支PHP 5.2.x-5.3.8爲好。html

安裝

這個庫遵循zend PSR-0標準。有一些自動加載器能夠自動加載這個庫,可是若是你不使用它,你能夠註冊OAuth2\Autoloadermysql

require_once('/path/to/oauth2-server-php/src/OAuth2/Autoloader.php'); OAuth2\Autoloader::register();

使用Composer執行如下命令:git

composer.phar require bshaffer/oauth2-server-php "^1.10"github

這會將需求添加到composer.json並安裝庫。web

強烈建議您查看v1.10.0標籤以確保您的應用程序不會由於向後兼容性問題而中斷。可是,若是您想保持開發的最前沿,您能夠將其設置爲dev-masterredis

開始使用這個庫

菜譜的例子是最好的入門方法。對於那些僅僅瀏覽代碼示例文檔的人來講,下面是一個簡單的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();

有關這個庫如何工做的更多信息,請參閱主要概念sql

學習OAuth2.0標準

  1. 若是您是OAuth2的新手,我強烈推薦Knp University的8步屏幕視圖中OAuth: 8個步驟中的OAuthshell

  2. 此外,花點時間點擊OAuth2演示應用程序, 並查看使用各類受權類型的示例 源代碼。 OAuth演示應用程序

  3. 並且,Auth0爲實現PHP應用程序的 OAuth2.0提供了一個很好的層次

  4. 最後,請查閱OAuth2.0官方文檔,瞭解不合理的技術規範。

 

主要概念

要更好地瞭解OAuth規範,請參閱 學習OAuth標準

圖書館涉及幾個主要概念:

Grant Types

授予類型容許您展現客戶端接收令牌的多種方式。

Controllers

OAuth服務器有3個端點,每一個端點均可以由控制器進行配置每一個端點都在OAuth進程中執行不一樣的功能。

  • 受權端點 - 用戶在這裏由客戶端重定向來受權請求
  • 令牌端點 - 客戶端向該端點發出請求以得到訪問令牌
  • 資源端點 - 客戶端請求資源,爲認證令牌提供訪問令牌。該庫支持許多不一樣的受權類型,包括由官方OAuth規範定義的全部受權類型。

Storage Objects

該庫使用存儲接口來容許與多個數據層進行交互。如下存儲類隨庫提供,但接口容許您自定義:

Other Concepts

 

授予類型

OAuth2規範中有許多支持的受權類型,而且該庫容許添加自定義受權類型。支持的受權類型以下:

受權碼

Authorization Code補助類型是最多見的OAuth2.0的流動。它實現3腿OAuth並涉及授予客戶一個受權碼,用戶能夠交換訪問令牌的用戶。點擊現場演示查看這個受權類型的實際操做。

資源全部者密碼憑證

資源全部者的用戶名和密碼做爲請求的一部分提交,而且在成功認證時發出令牌。

json
$ 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}

客戶端憑證

客戶端使用他們的憑證直接檢索訪問令牌,這容許在客戶端的控制下訪問資源

json
$ curl -u testclient:testpass "http://localhost/token.php" -d 'grant_type=client_credentials' {"access_token":"6f05ad622a3d32a5a81aee5d73a5826adb8cbf63","expires_in":3600,"token_type":"bearer","scope":null}

刷新令牌

若是訪問令牌已過時,客戶端能夠提交刷新令牌並接收新的訪問令牌。

json
$ 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 RequestsToken RequestsResource RequestsOAuth2\Server對象具備處理每一個請求的方法。

下面的每一個控制器經過相同的名稱對應於端點。

存儲

概觀

該庫支持多個不一樣存儲引擎的適配器。其中包括PDO(用於MySQL,SQLite,PostgreSQL等), MongoDBRedis和 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,請運行如下查詢:

sql
ALTER TABLE oauth_authorization_codes ADD id_token VARCHAR(1000) NULL DEFAULT NULL;

3.設置use_openid_connectissuer配置參數

// 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數據庫中:

sql
CREATE 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安全編碼:

json
{"typ": "JWT", "alg":"RS256"}

PAYLOAD是一個帶有如下字段的JSON對象的Base64 URL安全編碼:

json
{
  "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訪問令牌的響應:

json
{
    "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\AccessTokenInterfaceJwtAccessToken對象到具備存儲在一個附加的位置的訪問令牌:

$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在簽名後將授予的訪問令牌保存到存儲。

特定於客戶端的加密密鑰

製做特定於客戶端的密鑰是一個好主意。這樣,若是密鑰對受到攻擊,只有一個客戶端受到影響。雙方MemoryPdo支持這種類型的存儲。這裏是一個使用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,運行如下查詢:

sql
/* 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")

使用這樣的插入樣本數據:

sql
/* 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));
相關文章
相關標籤/搜索