oauth2-server-php-docs 概念

 

PHP的OAuth2服务器库

将OAuth2.0干净地安装到您的PHP应用程序中。 从GitHub 下载代码开始。

要求

这个库需要PHP 5.3.9+然而,有一个稳定的版本开发分支PHP 5.2.x-5.3.8为好。

安装

这个库遵循zend PSR-0标准。有一些自动加载器可以自动加载这个库,但是如果你不使用它,你可以注册OAuth2Autoloader

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

使用Composer执行以下命令:

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

这会将需求添加到composer.json并安装库。

强烈建议您查看v1.10.0标签以确保您的应用程序不会因为向后兼容性问题而中断。但是,如果您想保持开发的最前沿,您可以将其设置为dev-master

开始使用这个库

菜谱的例子是最好的入门方法。对于那些仅仅浏览代码示例文档的人来说,下面是一个简单的OAuth2服务器实现的例子:

$storage = new OAuth2StoragePdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
$server = new OAuth2Server($storage);
$server->addGrantType(new OAuth2GrantTypeAuthorizationCode($storage)); // or any grant type you like!
$server->handleTokenRequest(OAuth2Request::createFromGlobals())->send();

有关这个库如何工作的更多信息,请参阅主要概念

学习OAuth2.0标准

  1. 如果您是OAuth2的新手,我强烈推荐Knp University的8步屏幕视图中OAuth: 8个步骤中的OAuth

  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 OAuth2StoragePdo(array('dsn' => $dsn, 'username' => $username, 'password' => $password));
$server = new OAuth2Server($storage, array('allow_implicit' => true));

$server->handleAuthorizeRequest(OAuth2Request::createFromGlobals())->send();

重要的是要注意,这不是作为Grant Type添加的,因为隐式授权类型是使用authorize端点而不是token端点来请求

智威汤逊旗手

客户端可以向令牌端点提交请求中的JWT(JSON Web令牌)。然后直接返回一个访问令牌(没有刷新令牌)。

延期补助金

通过实现OAuth2GrantTypeGrantTypeInterface并将其添加到OAuth2服务器对象来创建您自己的授予类型JWT Bearer 上面格兰特类型就是一个例子。

多个授权类型

如果您想要支持多个授予类型,则可以在创建服务器对象时添加更多:

$server->addGrantType(new OAuth2GrantTypeUserCredentials($storage));
$server->addGrantType(new OAuth2GrantTypeRefreshToken($storage));
$server->addGrantType(new OAuth2GrantTypeAuthorizationCode($storage));

##限制授予类型给客户

客户机可用grant_type的授予类型由客户机存储器中的字段和授权服务器内提供的授予类型的组合来控制

当客户端拥有配置的授权类型列表时,客户端仅限于使用这些授予类型。如果没有配置授权类型,则客户端可以使用的授权类型不受限制,它可以使用授权服务器内可用的所有授权类型。

控制器

...最终用户(资源所有者)可以授予打印服务(客户端)访问存储在照片共享服务(资源服务器)中的受保护照片,而不必与打印服务共享她的用户名和密码。相反,她直接使用照片共享服务(授权服务器)信任的服务器进行身份验证,授权服务器发布打印服务委派特定凭据(访问令牌)。

〜OAuth2(草稿#31

大多数的OAuth2的API将有终点Authorize RequestsToken RequestsResource RequestsOAuth2Server对象具有处理每个请求的方法。

下面的每个控制器通过相同的名称对应于端点。

存储

概观

该库支持多个不同存储引擎的适配器。其中包括PDO(用于MySQL,SQLite,PostgreSQL等), MongoDBRedis和 Cassandra

这是通过多个PHP接口完成的,这个接口决定了如何存储不同的对象。接口允许对多个平台进行扩展和定制,使得编写自己的存储类容易 

存储接口还可以轻松地将对象存储在 多个数据存储系统中

请求和响应

请求对象

每个服务器调用都以一个请求开始。这个库使用自己的简单对象来验证对服务器的调用。你几乎总是会这样创建:

$request = OAuth2Request::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 = SymfonyComponentHttpFoundationRequest::createFromGlobals();
$request = OAuth2HttpFoundationBridgeRequest::createFromRequest($symfony_request)

// call the OAuth server with it
$server->handleTokenRequest($request);

响应对象

响应对象服务于使您的服务器符合OAuth2的目的。它将为有效或无效的oauth请求设置适当的状态码,标题和响应正文。要使用它作为最简单的级别,只需发送输出并退出:

$request = OAuth2Request::createFromGlobals();
$response = new OAuth2Response();

// 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用户向客户授权各种不同功能的能力(“访问基本信息”,“贴在墙上”等)。

在这个库中,范围是通过实现来处理的OAuth2StorageScopeInterface这可以使用你自己的实现,或者利用现有的OAuth2StorageMemory类来完成:

// configure your available scopes
$defaultScope = 'basic';
$supportedScopes = array(
  'basic',
  'postonwall',
  'accessphonenumber'
);
$memory = new OAuth2StorageMemory(array(
  'default_scope' => $defaultScope,
  'supported_scopes' => $supportedScopes
));
$scopeUtil = new OAuth2Scope($memory);

$server->setScopeUtil($scopeUtil);

这是最简单的方法,但范围也可以动态配置:

// configure your available scopes
$doctrine = Doctrine_Core::getTable('OAuth2Scope');
$scopeUtil = new OAuth2Scope($doctrine);

$server->setScopeUtil($scopeUtil);

这个例子假设正在使用的类实现OAuth2StorageScopeInterface

class OAuth2ScopeTable extends Doctrine_Table implements OAuth2StorageScopeInterface
{
    public function getDefaultScope($client_id = null)
    {
        //...
    }

    public function scopeExists($scope, $client_id = null)
    {
        //...
    }
}

验证你的范围

在服务器类中配置范围将确保客户端请求的范围是有效的。但是,要确保正确验证范围,需要执行两个步骤。首先,请求的范围必须在授权的情况下暴露给资源所有者。在这个库中,这个被实现了100%。用户界面或必须清楚授权的范围。其次,资源请求本身必须指定访问它所需的范围:

// https://api.example.com/resource-requiring-postonwall-scope
$request = OAuth2Request::createFromGlobals();
$response = new OAuth2Response();
$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以外的其他类别可能会有所帮助。OAuth2ScopeInterface在自定义类中实现以完全自定义。

state参数默认为授权重定向所必需的。这相当于一个CSRF令牌,并为您的授权请求提供会话验证。有关 状态的更多信息,请参阅OAuth2.0规范

为了安全起见,这是默认启用的,但是当你配置你的服务器时,你可以删除这个需求:

// on creation
$server = new OAuth2Server($storage, array('enforce_state' => false));

// or after creation
$server = new OAuth2Server();
$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”

然后这四个范围将根据使用OAuth2ScopeUtil该类的可用范围进行验证,以确保它们存在。如果您收到错误invalid_scope: An unsupported scope was requested,这是因为您需要在服务器对象上设置可用的作用域,如下所示:

$scope = new OAuth2Scope(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(OAuth2Request::createFromGlobals())) {
    $server->getResponse()->send();
    die;
}

$token = $server->getAccessTokenData(OAuth2Request::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 OAuth2StoragePdo(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 OAuth2Server($storage, $config);

4.创建您的密钥存储并将其添加到服务器:

$publicKey  = file_get_contents('/path/to/pubkey.pem');
$privateKey = file_get_contents('/path/to/privkey.pem');
// create storage
$keyStorage = new OAuth2StorageMemory(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 OAuth2Request(array(
    'client_id'     => 'SOME_CLIENT_ID',
    'redirect_uri'  => 'http://brentertainment.com',
    'response_type' => 'code',
    'scope'         => 'openid',
    'state'         => 'xyz',
));
$response = new OAuth2Response();
$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 OAuth2Server($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 OAuth2StorageMemory(array('keys' => array(
    'public_key'  => $publicKey,
    'private_key' => $privateKey,
)));

$server = new OAuth2Server($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');
OAuth2Autoloader::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 OAuth2StorageMemory(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 OAuth2Server($storage, array(
    'use_jwt_access_tokens' => true,
));
$server->addGrantType(new OAuth2GrantTypeClientCredentials($storage)); // minimum config

// send the response
$server->handleTokenRequest(OAuth2Request::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 OAuth2StorageMemory(array('keys' => array(
    'public_key'  => $publicKey,
)));

$server = new OAuth2Server($keyStorage, array(
    'use_jwt_access_tokens' => true,
));

这允许您的服务器验证访问令牌,而不向Authorization Server或任何其他共享资源发出任何请求。

// verify the JWT Access Token in the request
if (!$server->verifyResourceRequest(OAuth2Request::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!

使用辅助存储

该库允许您将访问令牌备份到辅助存储。只是通过实施一个对象OAuth2StorageAccessTokenInterfaceJwtAccessToken对象到具有存储在一个附加的位置的访问令牌:

$pdoStorage = new OAuth2StoragePdo($pdo); // access token will also be saved to PDO
$keyStorage = new OAuth2StorageMemory(array('keys' => array(
    'public_key'  => $publicKey,
    'private_key' => $privateKey,
)));

此示例从Memory存储中提取公钥/私钥,并Pdo在签名后将授予的访问令牌保存到存储。

特定于客户端的加密密钥

制作特定于客户端的密钥是一个好主意。这样,如果密钥对受到攻击,只有一个客户端受到影响。双方MemoryPdo支持这种类型的存储。这里是一个使用Memory存储的例子

$keyStorage = new OAuth2StorageMemory(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 OAuth2StoragePdo(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

在你的OAuth2StoragePublicKeyInterface实例中进行配置当使用Memory存储时,这看起来像这样:

$storage = new OAuth2StorageMemory(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));
原文地址:https://www.cnblogs.com/endv/p/7842515.html