goodid/goodid-php55-sdk

此包已被废弃,不再维护。作者建议使用goodid/goodid-php-sdk包。

PHP GoodID SDK

2.3.3 2018-03-19 22:03 UTC

This package is not auto-updated.

Last update: 2019-05-10 13:17:33 UTC


README

Build Status

注意: 此版本支持 >= PHP 5.5.9。如果您使用的是 PHP 5.6 或更高版本,我们建议您使用https://github.com/idandtrust/goodid-php-sdk

PHP 5.5 GoodID SDK

此仓库包含我们的开源 PHP SDK,允许您收集、解密和验证从用户那里接收到的数据。

安装

您可以使用Composer安装 GoodID PHP SDK。将 GoodID PHP SDK 包添加到您的 composer.json 文件中。

{
    "require": {
        "goodid/goodid-php55-sdk": "~2.0"
    }
}

前提条件

要为您的用户提供 GoodID 登录,您首先需要在 GoodID 上注册。您将获得 GoodID 移动应用测试版访问权限、GoodID 移动应用下载链接、客户端 ID、客户端密钥、默认密钥对和推荐的声明集。在此阶段,您还有机会生成自己的密钥对并将公钥发送到 GoodID。

GoodID 登录流程

这是对 GoodID 登录流程的简要介绍,让您了解在“要实现的端点”部分中将要实现的端点的目的。

GoodID 登录流程概述

  1. 当用户点击“使用 GoodID 登录”按钮时,GoodID JavaScript SDK 通过 AJAX 从您的 GoodID 登录初始化端点 获取一个新的“OpenID 身份验证请求”。
  2. GoodID JavaScript SDK 使用收到的“授权请求”打开 GoodID 登录页面,用户使用手机登录。
  3. 用户被重定向到您的 重定向 URI(着陆页面),带有“code”和“state”参数,这些参数由 GoodID PHP SDK 收集、解密和验证用户提供的信息。
  4. 恭喜!您已获取所有请求的用户数据。您可以进行登录或注册过程(如果是第一次使用给定的主题标识符登录)。

要实现的端点

GoodID 登录初始化端点

所谓的 GoodID 登录初始化端点 是 GoodID 的一个指定端点。它类似于 OpenID Connect 登录初始化端点。目前它负责以下事情:生成 OpenID 身份验证请求,并使 GoodID App-Initiated 登录流程(从提供商屏幕登录等)成为可能。该端点应是一个单独的 PHP 文件(例如,goodid-endpoint.php),其内容类似于以下代码片段。您不需要处理 GET/POST 参数或编写响应,这一切都由代码片段中实例化的 GoodID 端点自动完成。

// GoodID Login Initiation Endpoint (e.g. goodid-endpoint.php)

// Load the SDK and other dependencies
require_once __DIR__ . '/vendor/autoload.php';

use GoodID\Authentication\GoodIDEndpointFactory;
use GoodID\Exception\GoodIDException;
use GoodID\Helpers\Key\RSAPrivateKey;
use GoodID\Helpers\OpenIDRequestSource\OpenIDRequestObject;
use GoodID\ServiceLocator;

// -- Option 1 --
// You can use our default session data handler. 
// In this case you need to start the session first.
session_start();

$serviceLocator = new ServiceLocator();

// -- Option 2 --
// Or you can add your own session data handler
// by defining a class which implements \GoodID\Helpers\SessionDataHandlerInterface
// Add that to the $serviceLocator.
$serviceLocator->setSessionDataHandler(new CustomSessionDataHandler());

try {
    // Simply create and run our object, it will take care of everything
    GoodIDEndpointFactory::createGoodIDEndpoint(
        $serviceLocator,
        "YOUR-CLIENT-ID",
        new RSAPrivateKey("YOUR-SIG-PRIV-KEY-PEM-STRING"),
        new RSAPrivateKey("YOUR-ENC-PRIV-KEY-PEM-STRING"),
        new OpenIDRequestObject("YOUR-CLAIMS-JSON-STRING"),
        "YOUR-REDIRECT-URI"
    )->run();
} catch (GoodIDException $e) {
    error_log('Login initiation failed: ' . $e->getMessage());
    http_response_code(500);
    echo "Internal Server Error";
}

重定向URI(着陆页)

您还必须处理用户的登录请求。当用户使用GoodID登录时,他们将被重定向到您所谓的重定向URI,并带有“code”和“state”参数。您可以使用以下代码片段类似的东西。在登录(尝试)后进行重定向(强烈推荐),因为它从HTTP请求URL中删除查询参数,为用户提供更干净的用户体验。它还使他们的浏览器历史记录免受长期过期的授权代码的困扰。

// Redirect URI / landing page

require_once __DIR__ . '/vendor/autoload.php';

use GoodID\Authentication\GoodIDResponse;
use GoodID\Exception\GoodIDException;
use GoodID\Helpers\Key\RSAPrivateKey;
use GoodID\ServiceLocator;

// -- Option 1 --
// You can use our default session data handler. 
// In this case you need to start the session first.
session_start();

$serviceLocator = new ServiceLocator();

// -- Option 2 --
// Or you can add your own session data handler
// by defining a class which implements \GoodID\Helpers\SessionDataHandlerInterface
// Add that to the $serviceLocator.
$serviceLocator->setSessionDataHandler(new CustomSessionDataHandler());

// If there is a "code" parameter, it must be a login attempt
if (filter_has_var(INPUT_GET, 'code') || filter_has_var(INPUT_GET, 'error')) {
    try {
        // The GoodIDResponse object collects, decrypts and verifies the response data
        $response = new GoodIDResponse(
            $serviceLocator,
            "YOUR-CLIENT-ID",
            "YOUR-CLIENT-SECRET",
            new RSAPrivateKey("YOUR-SIG-PRIV-KEY-PEM-STRING"),
            new RSAPrivateKey("YOUR-ENC-PRIV-KEY-PEM-STRING")
        );

        if($response->hasError()) {
            $error = $gidResponse->getError();
            $errorDescription = $gidResponse->getErrorDescription();
            // The login has failed with an OpenID Authentication Error Response
            // For example the user pressed cancel in the app
        } else {
            // Subject identifier
            $subjectIdentifier = $response->getSub();
            // The data provided by the user
            $claims = $response->getClaims()->toArray();

            // For debugging:
//          echo "Sub: $subjectIdentifier\n";
//          echo "Claims: ";
//          print_r($claims);
//          exit;

            // Now begins the substantial part of the job:
            // You can do your custom validation of claims.
            // You can log in (or register) the user:
            // Read/write your DB, regenerate session id, etc.
            // Good luck :-)
        }
    } catch (GoodIDException $e) {
        // The login has failed with an exception
        // The identity of the user cannot be verified
        error_log('Login failed: ' . $e->getMessage());
    }

    header('Location: /');
    exit;
}

向GoodID发送自定义验证错误

当GoodID应用程序认为某些数据有效,但您的自定义验证认为它无效时,您可能希望通知我们。有了这些信息,我们可以使验证更好,或者帮助您调整您的claimset以获得更好的结果。您可以通过以下方式将错误日志发送给我们

use GoodID\Helpers\Logger\RemoteLogger;
use GoodID\Helpers\Logger\Log;
use GoodID\ServiceLocator;

// Assume $response is a GoodIDResponseObject, as seen in "Redirect URI (Landing page)"
// And assume you have validated phone_number and billto.phone_number and they both had some errors.
try {
    if($response->hasAccessToken()) {
        $logger = new RemoteLogger(
            $response->getAccessToken(),
            (new ServiceLocator())->getServerConfig()
        );
        $logger->log("phone_number", "Data does not conform to ...", Log::LEVEL_ERROR);
        $logger->log("billto.phone_number", "Data does not conform to ...", Log::LEVEL_ERROR);
        $logger->send();
    }
} catch (GoodIDException $e) {
    error_log('Remote logging failed: ' . $e->getMessage());
}

杂项

这些步骤可能在集成的某些步骤中很有用。

生成自己的密钥对

如果您希望生成自己的密钥对,以下是如何操作的,使用openssl在Ubuntu上安装openssl

sudo apt-get install openssl

生成密钥对

openssl genrsa -out client-enc_key.pem 2048
openssl rsa -in client-enc_key.pem -pubout > client-enc_key.pub
openssl genrsa -out client-sig_key.pem 2048
openssl rsa -in client-sig_key.pem -pubout > client-sig_key.pub

之后,请将以下内容发送给我们

  • 新的公钥对(.pub文件),并请将其标记,以便我们知道它们是为哪个环境准备的
  • 使用新的公钥创建的请求对象进行数字签名(根据下一段所述)

生成请求对象

作为集成的最后一步,您需要向GoodID发送一个经过签名的默认请求对象。GoodID将此发布到GoodID托管的“请求URI”,但为您创建的是唯一的。当从GoodID应用程序开始登录过程时,我们将从那里获取您签署的请求。它可以如下生成

use GoodID\Helpers\Key\RSAPrivateKey;
use GoodID\Helpers\OpenIDRequestSource\OpenIDRequestObject;
use GoodID\ServiceLocator;

$requestObject = new OpenIDRequestObject("Your claimset as a JSON string");
$jwt = $requestObject->generateJwt(
    new RSAPrivateKey("The content of your sig.pem as a string"),
    "Your client id",
    "Your default redirect URI",
    (new ServiceLocator())->getServerConfig()
);
echo $jwt;

生成JWKs URI的内容

您的JWKs URI是一个端点,它包含一个JWKSet,该JWKSet是一组以JSON格式表示的JSON Web密钥。您必须将您的签名和加密公钥存储在JWKs URI上,以便在应用启动的登录流程(例如,提供商屏幕)中轻松可用。

如果您还没有JWKs URI,您可以像这样生成其内容

use GoodID\Helpers\Key\JwkSetGenerator;
use GoodID\Helpers\Key\RSAPublicKey;

$sigKey = new RSAPublicKey("The content of your sig.pub as a string");
$encKey = new RSAPublicKey("The content of your enc.pub as a string");
$jwkSetGenerator = new JwkSetGenerator();
$jwksUriContent = $jwkSetGenerator->generateJwksUriContent($sigKey, $encKey);

如果您有一个现有的JWKs URI,并且您想向其中添加更多密钥,您可以按照以下描述进行操作。$jwksUriContent将包含您现有JWKs URI中的旧密钥以及通过参数传递的新密钥。

use GoodID\Helpers\Key\JwkSetGenerator;
use GoodID\Helpers\Key\RSAPublicKey;

$sigKey = new RSAPublicKey("The content of your sig.pub as a string");
$encKey = new RSAPublicKey("The content of your enc.pub as a string");
$jwkSetGenerator = new JwkSetGenerator();
$jwksUriContent = $jwkSetGenerator->generateJwksUriContent(
    $sigKey,
    $encKey,
    'https://your-url.com/jwksuri.json'
);

使用在picture_data声明中返回的图片

这仅对您有意义,如果您已请求用户的照片。您不必将图像写入文件,它只是一个示例。

// Assume that $response is a GoodID response
$claims = $response->getClaims();
$f = fopen('temporary.jpeg', 'wb');
fwrite($f, base64_decode($claims->get('picture_data')));
fclose($f);