effiana/oauth2-client

OAuth 2.0 客户端库

2.5.0 2020-07-18 17:54 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。如果你注意到符合性疏忽,请通过pull request发送补丁。如果你有兴趣为此库做出贡献,请参阅我们的贡献指南

要求

以下版本的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等),请查看我们的提供商客户端库列表提示:您可能正在寻找特定的提供商。

授权码授予类型是在使用第三方服务验证用户时最常用的授权类型。此授权类型利用客户端(本库)、服务器(服务提供者)和资源所有者(拥有受保护或拥有资源的凭证的用户)来请求访问用户拥有的资源。这通常被称为3方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

贡献

请参阅CONTRIBUTING以获取详细信息。

许可

MIT许可证(MIT)。请参阅许可文件以获取更多信息。