承接 benjaminfavre/oauth2-http-client 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

benjaminfavre/oauth2-http-client

Composer 安装命令:

composer require benjaminfavre/oauth2-http-client

包简介

A lightweight OAuth 2 decorator for the Symfony HTTP Client.

README 文档

README

A decorator for the Symfony HTTP Client that helps you call APIs endpoints protected with OAuth 2. It handles all the authentication protocol with the OAuth 2 server and let you focus solely on making your business API calls.

Designed to be minimalist and lightweight, it has literally no dependency at all, apart the Symfony Contracts of course; and it requires only the PHP JSON extension.

OAuth 2 is a relatively complex protocol which offers to authenticate in a wide variety of manners (called Grant Types in the OAuth jargon). This decorator aims to provide all standard Grant Types out of the box. Too often however, the OAuth 2 server you will have to authenticate to will not follow strict OAuth 2 standard. This is why the decorator has been designed such a way that every step of the authentication process is customizable.

Installation

composer require benjaminfavre/oauth2-http-client

Usage

use Symfony\Component\HttpClient\HttpClient;
use BenjaminFavre\OAuthHttpClient\OAuthHttpClient;
use BenjaminFavre\OAuthHttpClient\GrantType\ClientCredentialsGrantType;

$httpClient = HttpClient::create(); 

// Here we will use the client credentials grant type but it could be any other grant type
$grantType = new ClientCredentialsGrantType(
    $httpClient,
    'https://github.com/login/oauth/access_token', // The OAuth server token URL
    'the-client-id',
    'the-client-password'
);

$httpClient = new OAuthHttpClient($httpClient, $grantType);

// Then use $httpClient to make your API calls:
// $httpClient->request(...);

How it works

Each time you make an HTTP request, the decorator will:

  • Fetch an access token from cache or from the OAuth server if none is in cache;
  • Modify your request to add the access token (usually in a header);
  • Make the API call and return the response;
  • Optionally, try again with a new access token if the first API call failed because of token expiration.

Customization

Implement any of the following interfaces in order to customize the relevant authentication step, and pass an instance of your class via the relevant Decorator setter.

GrantTypeInterface

A class in charge of fetching an access token from the OAuth server. The decorator comes with four standard grant types:

  • AuthorizationCodeGrantType;
  • ClientCredentialsGrantType;
  • PasswordGrantType;
  • RefreshTokenGrantType.

TokensCacheInterface

A class in charge of storing and fetching tokens from cache. By default, the decorator uses MemoryTokensCache that caches the tokens in memory.

RequestSignerInterface

A class in charge of modifying the API request in order to add the access token. By default, the decorator uses BearerHeaderRequestSigner that adds the access token in the Authorization header. You can use the HeaderRequestSigner to add the access token in another header, or you can implement the interface for more customization.

ResponseCheckerInterface

A class in charge of checking if the API call failed because of a token expiration. By default, the decorator uses StatusCode401ResponseChecker that identifies 401 response codes as the signal the access token needs to be renewed. It can lead to false positives (401 response code can be returned for other reasons than token expiration), so you can implement the interface if your OAuth server returns exploitable fine-grained error reasons.

Full Symfony-specific example

Here is a full example of how to use this library inside a Symfony application.

  • with custom Grant Type
  • with Redis as a cache layer
  • with scoped HTTP Client definition
  • with different URLs for the OAuth server and the API

First of all, we need to define 2 HTTP Clients: one for the OAuth server and one for the API.

framework:
    http_client:
        scoped_clients:
            sharepoint_oauth.client:
                scope: '%env(resolve:SHAREPOINT_OAUTH_URL)%'
                headers:
                    Accept: 'application/json;odata=verbose'
                # other specific headers or settings if needed
            sharepoint_api.client:
                scope: '%env(resolve:SHAREPOINT_API_URL)%'
                headers:
                    Accept: 'application/json;odata=verbose'
                # other specific headers or settings if needed

Second, we need to define a custom Grant Type that will fetch the access token from the OAuth server to connect to SharePoint and will use sharepoint_oauth.client defined above.

It differs from a built-in ClientCredentialsGrantType on purpose, to show how we can customize the authentication process:

<?php

declare(strict_types=1);

namespace App\Sharepoint;

use BenjaminFavre\OAuthHttpClient\GrantType\GrantTypeInterface;
use BenjaminFavre\OAuthHttpClient\GrantType\Tokens;
use BenjaminFavre\OAuthHttpClient\GrantType\TokensExtractor;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\HttpClient\HttpClientInterface;

final class CustomClientCredentialsGrantType implements GrantTypeInterface
{
    use TokensExtractor;

    public function __construct(
        private HttpClientInterface $client,
        private string $sharepointOauthClientId,
        private string $sharepointOauthClientSecret,
        private string $sharepointOauthUrl,
        private string $sharepointOauthResource,
    ) {
    }

    public function getTokens(): Tokens
    {
        $response = $this->client->request(Request::METHOD_POST, $this->sharepointOauthUrl, [
            'body' => http_build_query([
                'grant_type' => 'client_credentials',
                'client_id' => $this->sharepointOauthClientId,
                'client_secret' => $this->sharepointOauthClientSecret,
                'resource' => $this->sharepointOauthResource,
            ]),
        ]);

        return $this->extractTokens($response);
    }
}

In order to pass the required parameters to the Grant Type, we need to define the service in service.yaml and bind parameters:

services:
    App\Sharepoint\CustomClientCredentialsGrantType:
        bind:
            $client: '@sharepoint_oauth.client'
            string $sharepointOauthClientId: '%env(SHAREPOINT_OAUTH_CLIENT_ID)%'
            string $sharepointOauthClientSecret: '%env(SHAREPOINT_OAUTH_CLIENT_SECRET)%'
            string $sharepointOauthResource: '%env(SHAREPOINT_OAUTH_RESOURCE)%'
            string $sharepointOauthUrl: '%env(SHAREPOINT_OAUTH_URL)%'

Then, we need to define our cache layer instead of default in-memory, by adding the following service definition to services.yaml:

BenjaminFavre\OAuthHttpClient\TokensCache\SymfonyTokensCacheAdapter:
    bind:
        $cache: '@cache.app'
        $cacheKey: 'sharepoint'

@cache.app is an application cache, configured in your system. In our example, this is a Redis cache:

framework:
    cache:
        app: cache.adapter.redis
        default_redis_provider: '%env(REDIS_URL)%'

Finally, we can define our OAuthHttpClient service in services.yaml that uses sharepoint_api.client and sets configured Redis cache:

BenjaminFavre\OAuthHttpClient\OAuthHttpClient:
    bind:
        $client: '@sharepoint_api.client'
        $grant: '@App\Sharepoint\CustomClientCredentialsGrantType'
    calls:
        - [ setCache, [ '@BenjaminFavre\OAuthHttpClient\TokensCache\SymfonyTokensCacheAdapter' ] ]

After this, OAuthHttpClient service is ready to be used in your application in any other classes:

public function __construct(
    private OAuthHttpClient $sharepointClient,
) {
}

benjaminfavre/oauth2-http-client 适用场景与选型建议

benjaminfavre/oauth2-http-client 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 1.36M 次下载、GitHub Stars 达 23, 最近一次更新时间为 2021 年 04 月 19 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「symfony」 「oauth」 「http-client」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 benjaminfavre/oauth2-http-client 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 benjaminfavre/oauth2-http-client 我们能提供哪些服务?
定制开发 / 二次开发

基于 benjaminfavre/oauth2-http-client 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 1.36M
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 24
  • 点击次数: 30
  • 依赖项目数: 3
  • 推荐数: 0

GitHub 信息

  • Stars: 23
  • Watchers: 1
  • Forks: 10
  • 开发语言: PHP

其他信息

  • 授权协议: Apache-2.0
  • 更新时间: 2021-04-19