ubitransport/oauth2-client

OAuth 2.0 客户端库

2.4.3 2020-07-08 09:48 UTC

README

此包使您轻松将应用程序集成到 OAuth 2.0 服务提供者。

Gitter Chat Source Code Latest Version Software License Build Status Scrutinizer Coverage Status Total Downloads

我们习惯于在网上看到那些“通过 Facebook/Google 等连接”按钮,社交网络集成现在是大多数 Web 应用程序的重要功能。许多这些网站使用名为 OAuth 2.0 的身份验证和授权标准(RFC 6749)。

此 OAuth 2.0 客户端库将与符合 OAuth 2.0 标准的任何 OAuth 提供者一起工作。默认情况下,我们提供了一个 GenericProvider,可用于连接到使用 Bearer tokens 的任何服务提供者(见下面的示例)。

许多服务提供者提供了超出 OAuth 2.0 标准的附加功能。因此,此库可以轻松扩展并包装以支持此附加行为。我们提供了链接到 所有已知的扩展此库的提供者客户端(即 Facebook、GitHub、Google、Instagram、LinkedIn 等)。如果您的提供者不在列表中,请随时添加。

此包符合 PSR-1PSR-2PSR-4PSR-7。如果您注意到合规性疏忽,请通过拉取请求发送补丁。如果您想为此库做出贡献,请查看我们的 贡献指南

要求

以下版本的 PHP 受支持。

  • PHP 5.6
  • PHP 7.0
  • PHP 7.1
  • PHP 7.2
  • PHP 7.3

提供者

官方 PHP League 提供者和第三方提供者的列表可以在 提供者列表 README 中找到。

要构建您自己的提供者,请参阅 提供者指南 README

用法

在大多数情况下,您可能希望使用特定的提供者客户端库,而不是此基本库。

查看 提供者列表 README,以查看提供者客户端库的列表。

如果使用 Composer 需求特定的提供者客户端库,您 无需也要求此库。Composer 会为您处理依赖关系。

授权码授权

以下示例使用此库提供的默认 GenericProvider。如果您正在寻找特定的提供者(例如 Facebook、Google、GitHub 等),请查看我们的 提供者客户端库列表提示:您可能正在寻找特定的提供者。

授权码授予类型是当使用第三方服务进行用户认证时最常用的授权类型。这种授权类型利用客户端(本库)、服务器(服务提供商)和资源拥有者(拥有受保护或所属资源的凭证的用户)来请求访问用户拥有的资源。这通常被称为三方OAuth,因为涉及三方。

以下示例使用Brent Shaffer的名为Lock'd In的演示OAuth 2.0应用程序来说明这一点。运行此代码时,您将被重定向到Lock'd In,在那里您将提示授权客户端代表您向资源发起请求。

现在,您实际上在Lock'd In上没有账户,但为了本例的目的,假设您在重定向到那里时已经在Lock'd In上登录。

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => 'demoapp',    // The client ID assigned to you by the provider
    'clientSecret'            => 'demopass',   // The client password assigned to you by the provider
    'redirectUri'             => 'http://example.com/your-redirect-url/',
    'urlAuthorize'            => 'http://brentertainment.com/oauth2/lockdin/authorize',
    'urlAccessToken'          => 'http://brentertainment.com/oauth2/lockdin/token',
    'urlResourceOwnerDetails' => 'http://brentertainment.com/oauth2/lockdin/resource'
]);

// If we don't have an authorization code then get one
if (!isset($_GET['code'])) {

    // Fetch the authorization URL from the provider; this returns the
    // urlAuthorize option and generates and applies any necessary parameters
    // (e.g. state).
    $authorizationUrl = $provider->getAuthorizationUrl();

    // Get the state generated for you and store it to the session.
    $_SESSION['oauth2state'] = $provider->getState();

    // Redirect the user to the authorization URL.
    header('Location: ' . $authorizationUrl);
    exit;

// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || (isset($_SESSION['oauth2state']) && $_GET['state'] !== $_SESSION['oauth2state'])) {

    if (isset($_SESSION['oauth2state'])) {
        unset($_SESSION['oauth2state']);
    }
    
    exit('Invalid state');

} else {

    try {

        // Try to get an access token using the authorization code grant.
        $accessToken = $provider->getAccessToken('authorization_code', [
            'code' => $_GET['code']
        ]);

        // We have an access token, which we may use in authenticated
        // requests against the service provider's API.
        echo 'Access Token: ' . $accessToken->getToken() . "<br>";
        echo 'Refresh Token: ' . $accessToken->getRefreshToken() . "<br>";
        echo 'Expired in: ' . $accessToken->getExpires() . "<br>";
        echo 'Already expired? ' . ($accessToken->hasExpired() ? 'expired' : 'not expired') . "<br>";

        // Using the access token, we may look up details about the
        // resource owner.
        $resourceOwner = $provider->getResourceOwner($accessToken);

        var_export($resourceOwner->toArray());

        // The provider provides a way to get an authenticated API request for
        // the service, using the access token; it returns an object conforming
        // to Psr\Http\Message\RequestInterface.
        $request = $provider->getAuthenticatedRequest(
            'GET',
            'http://brentertainment.com/oauth2/lockdin/resource',
            $accessToken
        );

    } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {

        // Failed to get the access token or user details.
        exit($e->getMessage());

    }

}

刷新令牌

一旦您的应用程序获得授权,您可以使用刷新令牌而不是整个获取新令牌的过程来刷新过期的令牌。为此,只需从您的数据存储中重用此刷新令牌来请求刷新。

此示例使用Brent Shaffer的名为Lock'd In的演示OAuth 2.0应用程序。有关详细信息,请参阅上面的授权码示例。

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => 'demoapp',    // The client ID assigned to you by the provider
    'clientSecret'            => 'demopass',   // The client password assigned to you by the provider
    'redirectUri'             => 'http://example.com/your-redirect-url/',
    'urlAuthorize'            => 'http://brentertainment.com/oauth2/lockdin/authorize',
    'urlAccessToken'          => 'http://brentertainment.com/oauth2/lockdin/token',
    'urlResourceOwnerDetails' => 'http://brentertainment.com/oauth2/lockdin/resource'
]);

$existingAccessToken = getAccessTokenFromYourDataStore();

if ($existingAccessToken->hasExpired()) {
    $newAccessToken = $provider->getAccessToken('refresh_token', [
        'refresh_token' => $existingAccessToken->getRefreshToken()
    ]);

    // Purge old access token and store new access token to your data store.
}

资源拥有者密码凭证授予

一些服务提供商允许您跳过授权码步骤,将用户的凭证(用户名和密码)交换为访问令牌。这被称为“资源拥有者密码凭证”授予类型。

根据OAuth 2.0标准第1.3.3节(强调部分)

凭证应仅在资源拥有者与客户端之间存在高度信任时使用(例如,客户端是设备操作系统的部分或高度特权应用程序),并且当其他授权授予类型不可用时(例如授权码)。

如果您支持授权码授予类型的服务提供商(见上文),我们不建议使用此授权类型,因为这通过允许用户认为可以信任第三方应用程序的凭据来强化了密码反模式

话虽如此,存在一些使用资源拥有者密码凭证授予类型是可以接受和有用的场景。以下是一个使用Brent Shaffer的名为Lock'd In的演示OAuth 2.0应用程序的例子。有关Lock'd In演示应用程序的详细信息,请参阅上面的授权码示例。

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => 'demoapp',    // The client ID assigned to you by the provider
    'clientSecret'            => 'demopass',   // The client password assigned to you by the provider
    'redirectUri'             => 'http://example.com/your-redirect-url/',
    'urlAuthorize'            => 'http://brentertainment.com/oauth2/lockdin/authorize',
    'urlAccessToken'          => 'http://brentertainment.com/oauth2/lockdin/token',
    'urlResourceOwnerDetails' => 'http://brentertainment.com/oauth2/lockdin/resource'
]);

try {

    // Try to get an access token using the resource owner password credentials grant.
    $accessToken = $provider->getAccessToken('password', [
        'username' => 'demouser',
        'password' => 'testpass'
    ]);

} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {

    // Failed to get the access token
    exit($e->getMessage());

}

客户端凭证授予

当您的应用程序代表自身访问其控制/拥有的服务提供商中的资源时,它可以使用客户端凭证授予类型。当您的应用程序的凭证存储在私有位置且永远不会暴露给最终用户(例如通过网页浏览器等)时,此授权类型最好使用。此授权类型的功能与资源拥有者密码凭证授予类型类似,但它不请求用户的用户名或密码。它只使用服务提供商颁发给您的客户端的客户端ID和密钥。

与前面的示例不同,以下示例不适用于功能正常的演示服务提供商。它仅作为示例提供。

// Note: the GenericProvider requires the `urlAuthorize` option, even though
// it's not used in the OAuth 2.0 client credentials grant type.

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => 'XXXXXX',    // The client ID assigned to you by the provider
    'clientSecret'            => 'XXXXXX',    // The client password assigned to you by the provider
    'redirectUri'             => 'http://my.example.com/your-redirect-url/',
    'urlAuthorize'            => 'http://service.example.com/authorize',
    'urlAccessToken'          => 'http://service.example.com/token',
    'urlResourceOwnerDetails' => 'http://service.example.com/resource'
]);

try {

    // Try to get an access token using the client credentials grant.
    $accessToken = $provider->getAccessToken('client_credentials');

} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {

    // Failed to get the access token
    exit($e->getMessage());

}

使用代理

可以使用代理来调试对提供者发出的HTTP调用。您只需在创建Provider实例时设置proxyverify选项即可。确保在代理中启用SSL代理。

$provider = new \League\OAuth2\Client\Provider\GenericProvider([
    'clientId'                => 'XXXXXX',    // The client ID assigned to you by the provider
    'clientSecret'            => 'XXXXXX',    // The client password assigned to you by the provider
    'redirectUri'             => 'http://my.example.com/your-redirect-url/',
    'urlAuthorize'            => 'http://service.example.com/authorize',
    'urlAccessToken'          => 'http://service.example.com/token',
    'urlResourceOwnerDetails' => 'http://service.example.com/resource',
    'proxy'                   => '192.168.0.1:8888',
    'verify'                  => false
]);

安装

通过Composer

$ composer require league/oauth2-client

贡献

有关详细信息,请参阅贡献

许可证

麻省理工学院许可(MIT)。请参阅许可文件以获取更多信息。