大卫森/oauth2-client

OAuth 2.0 客户端库

2.3.1 2017-06-05 10:21 UTC

README

此软件包简化了将您的应用程序与 OAuth 2.0 服务提供商集成的过程。从2.3.0版本(本存储库的第一个版本)开始,使用的 Guzzle 版本是 v5.3。为了支持这个旧版本的 Guzzle,我们进行了几项更新。

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

我们都习惯于在网上看到那些“通过 Facebook/Google 等”按钮,而社交网络集成是目前大多数网络应用的一个重要特性。许多这些网站使用名为 OAuth 2.0 的认证和授权标准(RFC 6749)。

此 OAuth 2.0 客户端库将与符合 OAuth 2.0 标准的任何 OAuth 提供商一起工作。开箱即用,我们提供了一个 GenericProvider,它可以用于连接到任何使用 Bearer 令牌 的服务提供商(请参见下面的示例)。

许多服务提供商在 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
  • HHVM

提供者

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

要构建自己的提供者,请参阅 提供者指南 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许可协议(MIT)。请参阅许可文件获取更多信息。