api-skeletons/laravel-doctrine-apikey

Laravel Doctrine 的 API 密钥,具有作用域

2.0.2 2024-04-13 02:49 UTC

This package is auto-updated.

Last update: 2024-09-13 03:43:16 UTC


README

Build Status Code Coverage PHP Version Total Downloads License

此仓库提供 Doctrine 的驱动程序,可以添加到现有的实体管理器中。
该驱动程序提供一组实体,通过 HTTP 中间件实现 ApiKey 授权。支持作用域!这是其他仓库中缺少的组件,也是创建此库的催化剂。

安装

运行以下命令使用 Composer 安装此库

composer require api-skeletons/laravel-doctrine-apikey

快速入门

将服务提供者添加到 app.php

    'providers' => [
        ...
        ApiSkeletons\Laravel\Doctrine\ApiKey\ServiceProvider::class,
    ],

将路由中间件添加到 Http Kernel

use ApiSkeletons\Laravel\Doctrine\ApiKey\Http\Middleware\AuthorizeApiKey;

$routeMiddleware = [
    ...
    'auth.apikey' => AuthorizeApiKey:class
];

App\Providers\AppServiceProvider 中初始化实体管理器的 ApiKey 服务

use ApiSkeletons\Laravel\Doctrine\ApiKey\Service\ApiKeyService;

public function boot()
{
    app(ApiKeyService::class)->init(app('em'));
}

通过控制台添加 API 密钥

$ php artisan apikey:generate yourapikeyname

将中间件添加到受保护的路由

Route::name('api.resource::fetch')
    ->get('resource', 'ResourceController::fetch')
    ->middleware('auth.apikey');

开始通过在 Authorization 标头的 Bearer token 中使用 apikey 向受保护的资源发送请求

Authorization: Bearer {apikey}

架构

Screen Shot 2021-12-17 at 12 20 03 AM

使用作用域

作用域是 ApiKey 的权限。它们在 OAuth2 中很常见,但在 ApiKey 中不太常见。创建一个作用域

php artisan apikey:scope:generate {name}

使用作用域进行的安全措施与用于验证 ApiKey 的相同中间件应用。将 {scopeName} 替换为您的范围名称,中间件将确保传递的 ApiKey 具有该范围以继续。

Route::name('api.resource::fetch')
    ->get('resource', 'ResourceController::fetch')
    ->middleware('auth.apikey:{scopeName}');

通过请求属性访问 ApiKey

用于验证请求的 ApiKey 实体被分配到请求属性作为 'apikey'。

$apiKey = request()->attributes->get('apikey');

使用外键到 ApiKey

由于 ApiKey 可以重新生成,因此没有必要将多个 API 密钥分配给同一实体。例如,如果每个客户都有一对一的 ApiKey,那么您可以安全地禁用该密钥,重新生成它,等等;永远不需要分配新的 ApiKey。

为了在客户实体和 API 密钥之间动态创建一对一关系,请创建一个事件订阅者

<?php

declare(strict_types=1);

namespace App\ORM\Event\Subscriber;

use ApiSkeletons\Laravel\Doctrine\ApiKey\Entity\ApiKey;
use App\ORM\Entity\Customer;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Events;

class ApiKeyEventSubscriber implements
    EventSubscriber
{
    /**
     * {@inheritDoc}
     */
    public function getSubscribedEvents()
    {
        return [
            Events::loadClassMetadata,
        ];
    }

    public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void
    {
        // the $metadata is the whole mapping info for this class
        $metadata = $eventArgs->getClassMetadata();

        switch ($metadata->getName()) {
            case Customer::class:
                $metadata->mapOneToOne([
                    'targetEntity' => ApiKey::class,
                    'fieldName' => 'apiKey',
                ]);
                break;
            default:
                break;
        }
    }
}

事件日志

当 ApiKey 生成、激活、禁用、添加作用域和删除作用域时,将记录管理事件。

当路由中间件允许访问资源时,将记录访问事件。

命令

API 密钥的管理通过命令行处理。但是,可以通过 Doctrine 存储库(ApiKeyRepository 和 ScopeRepository)完全访问所有数据创建函数。

生成 ApiKey

php artisan apikey:generate {name}

生成作用域

php artisan apikey:scope:generate {name}

将作用域分配给 ApiKey

php artisan apikey:scope:add {apiKeyName} {scopeName}

禁用 ApiKey

php artisan apikey:deactivate {name}

激活 ApiKey

php artisan apikey:activate {name}

从 ApiKey 中取消分配作用域

php artisan apikey:scope:remove {apiKeyName} {scopeName}

重新生成 ApiKey(分配新的 Bearer token)

php artisan apikey:regenerate {name}

删除作用域

php artisan apikey:scope:delete {scopeName}

打印 ApiKey[s]

php artisan apikey:print {name?} 

打印 Scope[s]

php artisan apikey:scope:print {name?} 

多个对象管理器

此仓库包含的元数据可以在多个对象管理器中正常工作。
此仓库包含的命令仅在默认 ApiKeyService 上工作,因此您需要第二种方法来维护第二个对象管理器中的数据。为了使用多个对象管理器,您必须进行一些配置。假设您已经遵循了上面的快速入门步骤,请按照以下步骤进行第二个对象管理器的配置

App\Providers\AppServiceProvider 中创建 ApiKeyService 的一个新单例,并使用不同的名称

use ApiSkeletons\Laravel\Doctrine\ApiKey\Service\ApiKeyService;

public function register(): void
{
    $this->app->singleton('ApiKeyService2', static function ($app) {
        return new ApiKeyService();
    });
}

App\Providers\AppServiceProvider 中为第二个实体管理器初始化 ApiKey 服务

public function boot()
{
    app('ApiKeyService2')->init(app('em2'));
}

将路由中间件复制到一个新类,并使用依赖注入为 ApiKeyService2 使用

$routeMiddleware = [
    ...
    'auth.apikey2' => EditedAuthorizeApiKey:class
];

灵感来源于

这个仓库的灵感来源于https://github.com/ejarnutowski/laravel-api-key。它是一个不错的项目,但没有单元测试或作用域。