p7s1-ctf / 7pass-php-sdk
PHP 7Pass SDK
Requires
- php: >=5.5.0
- ext-curl: *
- lib-curl: *
- firebase/php-jwt: ~3.0
- guzzlehttp/guzzle: ~6.0
- phpseclib/phpseclib: 0.3.*
- tedivm/stash: 0.14.*
Requires (Dev)
- munkie/phpunit-teamcity-testlistener: dev-master#94bd42157940c305a8f02c3d8b0574e8529e1404
- php-vcr/php-vcr: 1.2.8
- php-vcr/phpunit-testlistener-vcr: ~1.1
- phpunit/phpunit: 4.8.*
README
7Pass PHP SDK 是一个用于与 7Pass SSO 服务 交互的 PHP 库。您可以使用此库来实现您网站的认证,并利用 7Pass SSO 提供的现有功能。
安装
在开始使用库之前,请确保您的系统满足所需的条件。目前,该库需要 PHP 5.5.0 及以上版本,并支持 cURL。
注意:生产环境和 qa 环境只接受 TLS v1.2 连接 - 请确保您的系统 cURL 库支持它,否则会抛出 SSL connect error
异常。
该库以 composer 包的形式分发。如果您还没有安装,请使用 Composer 的官方说明进行安装。安装 Composer 后,您可以通过以下方式安装库
$ composer require p7s1-ctf/7pass-php-sdk
这将自动将库添加到您应用程序依赖项列表中。
运行示例应用程序
为了演示库的功能,有一个交互式教程/指南可用。在开始设置之前,您需要您的 Web 应用程序客户端。客户端代表您想要认证的服务关联的实体。
要获取客户端凭据,您首先需要联系 7Pass 技术团队。
一旦您有了可用的凭据,您就可以继续安装依赖项
$ composer install
接下来,您可以转到 public_html
目录并创建本地配置文件
$ cd public_html
$ cp config.local.php.example config.local.php
使用您最喜欢的编辑器编辑 config.local.php
文件并填写详细信息。在客户端设置完成后,您应该可以使用所有参数。为了测试,请将环境设置为 qa
。完成后,您可以使用 PHP 内置服务器启动应用程序
$ php -S localhost:8000
示例应用程序现在应在 https://:8000
上可用。应用程序将引导您了解库的常见用法,并在过程中展示代码示例和服务器响应。
API 使用
强烈建议您首先查看示例应用程序。它将显示带有更多注释和实际值的 API 调用。随着您的前进,它还将显示 7Pass SSO 服务的真实响应。
要使用库,必须使用我们想要使用的客户端的凭据对其进行初始化。如果您还没有凭据,请参阅上文。
- client_id(必需)
- client_secret(必需)
如果您开始开发,始终建议您针对 7Pass SSO 服务的非实时实例进行工作。要指定您想要发出请求的实例(环境),您可以将一个额外的键名为 environment 传递给配置。目前运行有两个环境:QA 和生产。在您将应用程序发布给公众之前,别忘了切换到生产版本。
$config = [ 'client_id' => 'YOUR_CLIENT_ID', 'client_secret' => 'YOUR_CLIENT_SECRET', 'environment' => 'qa' // Optional, defaults to 'production' ]; // Creates the configuration object $ssoConfig = new P7\SSO\Configuration($config); // Pass the configuration to the SSO object $sso = new P7\SSO($ssoConfig);
对于这两种环境,都有一个默认的 host
URL,7Pass API 端点可以通过它访问。对于 生产
环境,它是 https://sso.7pass.de,而对于 qa
环境,主机为 https://sso.qa.7pass.ctf.prosiebensat1.com。如果需要,可以通过在配置中指定 host
来覆盖它,如下所示
$config = [
'host' => 'https://mysubdomain.7pass.de'
// ... other config values
];
认证流程
认证过程很简单,其高级视图如下:用户通过一个特别定制的 URL 被重定向到 7Pass SSO 服务并登录(或注册)。一旦用户完成流程,他们将被带回到您的应用程序,URL 中有一个特殊代码。然后应用程序将使用该代码来获取用户详细信息。具体流程可能因传递的选项而异。
1. 获取重定向 URL
库会自动处理生成用户需要重定向到的 URL。唯一的必需参数是 redirect_uri
URL。该 URL 需要是绝对路径,可以是任意的(只要它在客户端注册了),但根据惯例应指向同一主机和一个名为 "callback" 的路由。
state 参数的使用是可选的但推荐使用,以避免 CSRF 攻击——该值通常存储在会话中,并在处理回调请求时与 $sso->authorization()->callback()
方法一起使用。
$callbackUri = 'https://example.com/callback'; $options = [ 'redirect_uri' => $callbackUri, // Required. 'scope' => 'openid profile email', // Optional, default value. 'response_type' => 'code' // Optional, default value. 'state' => $sessionState // Optional, but recommended to avoid CSRF attacks ]; $redirectUrl = $sso->authorization()->authorizeUri($options);
库将自动设置 client_id
和 nonce
(一个唯一的请求标识符)参数。
2. 重定向用户
现在需要将用户重定向到生成的 URL。在纯 PHP 中,你可以设置 Location
头部
header('Location: ' . $redirectUrl); exit;
3. 处理 7Pass 回调
用户完成登录/注册对话框后,他们会被重定向到重定向 URI URL,并带有登录过程的成果。用户可能已成功认证,也可能选择取消流程或发生其他错误。因此,适当的错误处理很重要。
无论何时发生错误,URL 中都会出现两个查询参数 - error 和 error_description
。error 参数包含错误代码,error_description 包含对错误的可读描述。处理错误并向最终用户显示适当的消息。
你可以选择如下手动处理错误。否则,如果发生错误,调用 $sso->authorization()->callback()
方法将抛出 AuthorizeCallbackException。
if(!empty($_GET['error'])) { $error = $_GET['error']; $errorDescription = $_GET['error_description']; // Handle the error and display appropriate message to your end-user. }
库会自行处理检索令牌,你只需要提供 redirect_uri
以及来自请求的查询参数,这些参数应包括 code
。这允许你检索可用于稍后获取有关用户实际信息的令牌。这些令牌对特定用户是特定的,并且是私有的。你需要确保它们的安全,不要与任何人分享。
$sessionState
参数是可选的,但如果与 $sso->authorization()->authorizeUri()
方法一起使用,则应提供相同的值。当提供的 state 值与从查询参数 $_GET 中检索的值不匹配时,将抛出 AuthorizeCallbackException。
$tokens = $sso->authorization()->callback($callbackUri, $_GET, $sessionState);
接收到的响应将具有以下结构。运行示例应用程序以查看实际值。
P7\SSO\TokenSet( [access_token] => ACCESS_TOKEN [token_type] => 'Bearer' [refresh_token] => REFRESH_TOKEN [expires_in] => 7200 [id_token] => JWT_STRING [id_token_decoded] => DECODED_JWT, [received_at] => RECEIVED_AT_TIMESTAMP )
注意:从id_token
字段解码并验证id_token_decoded
值。如果令牌验证失败,将抛出P7\SSO\Exception\TokenVerificationException
异常。
此外,如果code
已经被使用或无效,调用可能会抛出P7\SSO\Exception\ApiException
异常。
4. 缓存访问令牌
令牌以类型为P7\SSO\TokenSet
的单个对象表示。您可以直接序列化该对象,但我们建议您首先将TokenSet
转换为更简单的数组对象,并对其进行序列化。一旦需要再次使用TokenSet
,您可以将数组对象传递给其构造函数。
// Serialize the TokenSet object and store it in e.g. the current session $_SESSION['tokens'] = $tokens->getArrayCopy(); // Deserialize and get the TokenSet object again $tokens = new \P7\SSO\TokenSet($_SESSION['tokens']);
访问令牌的有效期为expires_in
字段中指定的秒数。一旦访问令牌过期,它就无法再使用。您可以使用以下方式使用刷新令牌获取新的令牌
if($tokens->isAccessTokenExpired()) { $tokens = $sso->authorization()->refresh([ 'refresh_token' => $tokens->refresh_token ]); }
注意:上述refresh()
方法也接受P7\SSO\TokenSet
对象作为参数。
5. 调用我们的API端点
既然我们已经确认令牌是最新的,我们就可以开始向7Pass SSO服务发送请求以获取用户数据。
与前面的示例相同,运行示例应用程序以查看实际的服务器响应。
$accountClient = $sso->accountClient($tokens); $response = $accountClient->get('me');
7Pass SSO服务提供了相当多的这些端点。要了解更多信息,您可以访问官方文档的概述。
客户端凭据请求
库支持多种类型的“客户端”。这些客户端通常在所需的配置参数以及之后的功能上有所不同。“客户端凭据”客户端是一种特殊的客户端,它不与用户账户相关联,只能用于调用“客户端”API。
您可以在文档中查看所有可用的端点,其中accessType参数等于client
。
$config = [ 'environment' => 'qa', // Optional, defaults to 'production', 'client_id' => 'CLIENT_ID', 'client_secret' => 'CLIENT_SECRET' ]; // Creates the configuration object $ssoConfig = new P7\SSO\Configuration($config); // Pass the configuration to the SSO object $sso = new P7\SSO($ssoConfig); // Get the tokens using the client credentials grant type $tokens = $sso->authorization()->clientCredentials(); // Use the client $client = $sso->clientCredentialsClient($tokens); $response = $client->post('checkPassword', [ 'password' => 'PASSWORD' ]);
设备流程
通过设备流程,人们可以轻松、安全地使用7Pass账户在输入或显示功能有限的设备上登录应用程序和服务。这包括智能电视、数字相框或物联网设备。
设备(您的应用程序)指示最终用户使用另一台计算机或设备连接到7Pass以批准访问请求。由于您的应用程序无法接收传入的请求,它将反复轮询7Pass授权服务器,直到最终用户完成批准过程。
您的应用程序通过向令牌端点发出HTTP POST请求以从授权服务器请求一组验证码来启动流程。
$deviceCodeResponse = $sso->authorization()->deviceCode();
$deviceCodeResponse
将是如下所示的stdClass对象
stdClass(
[code] => CODE // used along with poll requests (see below)
[user_code] => Q9CFLH // the code which user should enter on LINK page
[expires_in] => 600 // expiration of the code (in seconds)
[interval] => 5 // recommended interval for repeating poll requests (in seconds)
[link] => LINK_URL // verification URL user should use to authenticate
[link_qr] => IMAGE_URL // image URL of QR code encoded link
)
现在应提示用户访问另一个设备上的link
URL以输入user_code
。link_qr
是表示QR代码的link
URL的图像的URL。这可以供使用移动设备的用户使用,他们可以扫描它,并在他们的移动浏览器中打开link
URL,而无需手动输入。
当用户尝试在link
URL上进行身份验证时,您的应用程序将反复轮询7Pass服务器。建议的间隔由interval
值指定。
以下示例中的$code
可以是来自$sso->authorization()->deviceCode()
方法调用的$deviceCodeResponse
对象,包含code
项的数组,或者简单地是一个包含code
值的字符串。
// repeat every [interval] seconds.
try {
$response = $sso->authorization()->deviceCodePoll($code);
if($response instanceof \P7\SSO\TokenSet) {
// stop polling - user has authorized from another device successfully
}
// $reponse === false in case 'authorization_pending' response is received
} catch(ApiException $e) {
// handle the error appropriately
// $e->getError() is set to one of error codes 'code_expired', 'slow_down', 'invalid_grant'
}
后台请求
库也可以用来执行“后台”请求。这些请求无需用户直接参与,旨在用于管理目的。您的客户端需要允许backoffice_code
授权类型。您还需要知道您要与之工作的用户的ID。
后台请求用于代表其他用户进行API调用。要获取这些请求的访问令牌,您需要使用特殊的授权类型'backoffice_code'并提供account_id
。在成功验证后,您将获得与使用上述标准流程相同的令牌集。
$config = [ 'environment' => 'qa' // Optional, defaults to 'production', 'service_id' => 'SERVICE_ID', // Required for backoffice access 'backoffice_key' => 'BACKOFFICEC_KEY' // Required for backoffice access ]; // Creates the configuration object $ssoConfig = new P7\SSO\Configuration($config); // Pass the configuration to the SSO object $sso = new P7\SSO($ssoConfig); // Get the tokens using the backoffice $tokens = $sso->authorization()->backoffice([ 'account_id' => 'account_id' // Required, the ID of the user you want to access ]); // Use the client as you normally would when using the standard access $accountClient = $sso->accountClient($tokens); $response = $accountClient->get('me');
响应将像往常一样。一旦您获得令牌,7Pass SSO服务将表现得就像使用“标准”方式获得了访问令牌。
客户端/后台注册
当您使用客户端或后台注册API注册新用户时,您可能希望将他们重定向到7Pass SSO服务,以便创建用户的会话并登录用户。
此SDK提供了一个名为autologinUri()
的方法,可以用来生成重定向(跳转)URL。该方法接受一个TokenSet
作为其第一个参数。您可以通过提供scope
参数在使用注册API时检索用户的令牌。有关更多详细信息,请参阅注册API文档。response_type
默认为none
,但根据需要可以设置为任何其他支持类型。
// $client is an instance of ApiClient created using $sso->clientCredentialsClient() or $sso->backofficeClient() methods.
$response = $client->post('registration', [
'scope' => 'openid profile email'
// other parameters
]);
$tokens = TokenSet::receiveTokens($response);
$callbackUri = 'https://example.com/callback';
$uri = $sso->authorization()->autologinUri($tokens, [
'redirect_uri' => $callbackUri, // Required
'state' => $sessionState // Optional but recommended to use
], [
'remember_me' => true // Default value: false
])
// Redirect user to $uri
与其他普通授权请求一样,您可以使用Authorization::callback()
方法来处理回调请求。如果response_type
被设置为none
,则该方法返回null
。
$tokens = $sso->authorization()->callback($callbackUri, $_GET, $sessionState);
缓存
在库能正常工作之前,它需要从配置的7Pass SSO服务的实例中获取OpenID配置。为了确保信息不会每次都下载,库使用可配置的缓存机制。
默认的过期时间为1小时,可以通过向$config
设置(以秒为单位)传递cache_config_openid_ttl
值来自定义。
库内部会从传递给配置构造函数的所有参数中计算出一个哈希值,并将其用作配置的缓存键。这意味着如果配置发生变化,库将自动重新发现配置。
然而,请注意,如果配置被改回某些先前使用过的状态,并且计算出的配置的键对应于现有的缓存项,您可能会得到一个过时的配置。如果您预计远程OpenID配置会发生变化,您可以清除缓存并让库自行重新发现它,或者您可以有条件地运行rediscover()
方法。
在底层,它使用了Stash Caching Library库,并尝试首先使用Apc驱动。如果不可用,它将使用Filesystem驱动。
如果需要,您可以按照以下方式配置自己的缓存驱动程序
$config = [ // ... other configuration settings 'cache_config_openid_ttl' => 3600 // sets cache expiration time to 1 hour ]; $ssoConfig = new P7\SSO\Configuration($config); $driver = new Stash\Driver\Memcache(['servers' => ['127.0.0.1', '11211']]); $ssoConfig->setCachePool(new Stash\Pool($driver)); $sso = new P7\SSO($ssoConfig);
要手动刷新缓存,请使用rediscover
方法。在正常情况下,通常不需要这样做。
$sso->getConfig()->rediscover();
如果您有任何疑问或发现某些功能不符合预期,请随时联系7Pass技术团队。
运行测试
该库使用PHPUnit进行测试。推荐版本为4.8,尽管测试也可能在4系列较旧版本上成功运行。
$ composer install $ ./vendor/bin/phpunit