allangallop/laravel-xero-oauth2-multi-tenant

基于webfox/laravel-xero-oauth2修改,支持多租户使用的分支

3.0.1 2022-06-09 13:24 UTC

This package is auto-updated.

Last update: 2024-09-08 21:14:30 UTC


README

Latest Version on Packagist Total Downloads

本包使用 OAuth 2.0 规范与 Laravel 集成推荐的 xeroapi/xero-php-oauth2

安装

您可以通过以下命令使用 composer 安装此包

composer require allangallop/laravel-xero-oauth2-multi-tenant

此包将自动注册自己。

您应该使用以下键将您的 Xero 密钥添加到您的 .env 文件中

XERO_CLIENT_ID=
XERO_CLIENT_SECRET=

(在 Xero 开发者门户 上):重要 在 Xero 中设置应用程序时,请确保您的重定向 URL 是

https://{your-domain}/xero/auth/callback

(流程是 xero/auth/callback 执行 OAuth 握手并存储您的令牌,然后重定向您到您的成功回调)

您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="Webfox\Xero\XeroServiceProvider" --tag="config"

作用域

您需要在配置文件中设置应用程序所需的作用域。

默认的作用域集合包括 openidemailprofileoffline_accessaccounting.settings。您可以在 官方 Xero 文档 上查看所有可用的作用域。

使用包

此包将两个绑定注册到服务容器中,您可能会感兴趣的是

  • \XeroAPI\XeroPHP\Api\AccountingApi::class 这是 Xero 的主要 API - 请参阅 xeroapi/xero-php-oauth2 文档 了解用法。当您第一次解决此依赖项时,如果存储的凭证已过期,它将自动刷新令牌。
  • Webfox\Xero\OauthCredentialManager 这是凭证管理器 - 财务 API 需要我们在每个请求中传递租户 ID,这个类就是如何访问它的。这也可以获取有关认证用户的信息。以下是一个示例。

app\Http\Controllers\XeroController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Webfox\Xero\OauthCredentialManager;

class XeroController extends Controller
{

    public function index(Request $request, OauthCredentialManager $xeroCredentials)
    {
        try {
            // Check if we've got any stored credentials
            if ($xeroCredentials->exists()) {
                /* 
                 * We have stored credentials so we can resolve the AccountingApi, 
                 * If we were sure we already had some stored credentials then we could just resolve this through the controller
                 * But since we use this route for the initial authentication we cannot be sure!
                 */
                $xero             = resolve(\XeroAPI\XeroPHP\Api\AccountingApi::class);
                $organisationName = $xero->getOrganisations($xeroCredentials->getTenantId())->getOrganisations()[0]->getName();
                $user             = $xeroCredentials->getUser();
                $username         = "{$user['given_name']} {$user['family_name']} ({$user['username']})";
            }
        } catch (\throwable $e) {
            // This can happen if the credentials have been revoked or there is an error with the organisation (e.g. it's expired)
            $error = $e->getMessage();
        }

        return view('xero', [
            'connected'        => $xeroCredentials->exists(),
            'error'            => $error ?? null,
            'organisationName' => $organisationName ?? null,
            'username'         => $username ?? null
        ]);
    }

}

resources\views\xero.blade.php

@extends('_layouts.main')

@section('content')        
@if($error)
    <h1>Your connection to Xero failed</h1>
    <p>{{ $error }}</p>
    <a href="{{ route('xero.auth.authorize') }}" class="btn btn-primary btn-large mt-4">
        Reconnect to Xero
    </a>
@elseif($connected)
    <h1>You are connected to Xero</h1>
    <p>{{ $organisationName }} via {{ $username }}</p>
    <a href="{{ route('xero.auth.authorize') }}" class="btn btn-primary btn-large mt-4">
        Reconnect to Xero
    </a>
@else
    <h1>You are not connected to Xero</h1>
    <a href="{{ route('xero.auth.authorize') }}" class="btn btn-primary btn-large mt-4">
        Connect to Xero
    </a>
@endif
@endsection

routes/web.php

/* 
 * We name this route xero.auth.success as by default the config looks for a route with this name to redirect back to
 * after authentication has succeeded. The name of this route can be changed in the config file.
 */
Route::get('/manage/xero', [\App\Http\Controllers\XeroController::class, 'index'])->name('xero.auth.success');

多租户

对于多租户场景,您可以从 Webfox\Xero\OauthCredentialManager 调用 getTenants() 方法,这将返回一个当前连接的组织的数组

$xeroCredentials->getTenants();
/** 
* Array
* (
*    [0] => Array
*    (
*    [Id] =>c5929985-9c2b-4ec9-84ee-406be3596249
*    [Name] => Example Company A
*    )
*    [1] => Array
*    (
*    [Id] => 939d5c21-7069-4010-b6f1-7520172f214c
*    [Name] => Example Company B
*    )
* )
 **/

同样,getTenantId() 已扩展为接受索引键作为参数(如果为空,默认为 0)

$xeroCredentials->getTenantId();
// Returns c5929985-9c2b-4ec9-84ee-406be3596249

$xeroCredentials->getTenantId(0);
// Returns c5929985-9c2b-4ec9-84ee-406be3596249

$xeroCredentials->getTenantId(1);
// Returns 939d5c21-7069-4010-b6f1-7520172f214c

这些提供了实现您自己的多租户组织逻辑的方法,例如

...

    /**
     * Retrieve all contacts for given tenant
     * @access public
     * @param  integer $tenant
     * @throws Exception Credentials invalid
     * @return Array Contacts
     **/
    public function getContacts(int $tenant): array
    {
        if ($xeroCredentials->exists()) {
            $xero = resolve(\XeroAPI\XeroPHP\Api\AccountingApi::class);    
            return = $xero->getContact($xeroCredentials->getTenantId($tenant));
        }else{
            throw new \Exception("Credentials are invalid");
        }
    }
...

凭证存储

凭证存储在 Laravel 文件系统默认磁盘上的 JSON 文件中,可见性设置为私有。这允许使用共享磁盘(如 S3)跨多个服务器共享凭证,无论哪个服务器进行了 OAuth 流。

要使用不同的磁盘,将 xero.credential_disk 配置项更改为在 config/filesystem.php 中定义的另一个磁盘。

您可以通过两种方式切换凭证存储(例如,如果您想要将凭证存储在您的 UserStore 中)

  1. 如果它是一个简单的存储,Laravel 可以自动解析您的绑定,只需将 xero.credential_store 配置键更改为指向您的新实现即可。
  2. 如果它需要更复杂的逻辑(例如,使用当前用户检索凭证),则可以在您的 AppServiceProvider 或中间件中重新绑定此操作,例如
$this->app->bind(OauthCredentialManager::class, function(Application $app) {
    return new UserStorageProvider(
        \Auth::user(), // Storage Mechanism 
        $app->make('session.store'), // Used for storing/retrieving oauth 2 "state" for redirects
        $app->make(\Webfox\Xero\Oauth2Provider::class) // Used for getting redirect url and refreshing token
    );
});

一个示例 UserStorageProvider 可以在这里找到

使用 Webhooks

在 Xero 开发者门户中的您的应用中创建一个 webhook 以获取您的 webhook 密钥。

然后您可以将它添加到您的 .env 文件中,如下所示

XERO_WEBHOOK_KEY=...

然后您可以设置一个控制器来处理您的 webhook 并注入 \Webfox\Xero\Webhook,例如:

<?php

namespace App\Http\Controllers;

use Webfox\Xero\Webhook;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use XeroApi\XeroPHP\Models\Accounting\Contact;
use XeroApi\XeroPHP\Models\Accounting\Invoice;

class XeroWebhookController extends Controller
{
    public function __invoke(Request $request, Webhook $webhook)
    {

        // The following lines are required for Xero's 'itent to receive' validation
        if (!$webhook->validate($request->header('x-xero-signature'))) {
            // We can't use abort here, since Xero expects no response body
            return response('', Response::HTTP_UNAUTHORIZED);
        }

        // A single webhook trigger can contain multiple events, so we must loop over them
        foreach ($webhook->getEvents() as $event) {
            if ($event->getEventType() === 'CREATE' && $event->getEventCategory() === 'INVOICE') {
                $this->invoiceCreated($request, $event->getResource());
            } elseif ($event->getEventType() === 'CREATE' && $event->getEventCategory() === 'CONTACT') {
                $this->contactCreated($request, $event->getResource());
            } elseif ($event->getEventType() === 'UPDATE' && $event->getEventCategory() === 'INVOICE') {
                $this->invoiceUpdated($request, $event->getResource());
            } elseif ($event->getEventType() === 'UPDATE' && $event->getEventCategory() === 'CONTACT') {
                $this->contactUpdated($request, $event->getResource());
            }
        }

        return response('', Response::HTTP_OK);
    }

    protected function invoiceCreated(Request $request, Invoice $invoice)
    {
    }

    protected function contactCreated(Request $request, Contact $contact)
    {
    }

    protected function invoiceUpdated(Request $request, Invoice $invoice)
    {
    }

    protected function contactUpdated(Request $request, Contact $contact)
    {
    }

}

示例调用

这个包只是一个桥梁,您不需要处理 Laravel 中的 Oauth2 复杂操作。

一旦您有了一个 \XeroAPI\XeroPHP\Api\AccountingApi::class 的实例,您就正在直接与 Xero 的 API 库打交道。

XeroAPI PHP Oauth2 App 存储库有实现 API 调用的示例列表:例如发票创建等。

https://github.com/XeroAPI/xero-php-oauth2-app/blob/master/example.php

许可证

MIT 许可证(MIT)。有关更多信息,请参阅许可证文件