drewlabs/laravel-http-guard

Laravel/Lumen 使用 HTTP 协议接口的认证保护器

v0.3.2 2024-06-24 13:56 UTC

This package is auto-updated.

Last update: 2024-09-16 01:54:35 UTC


README

使用 OAuth bearer 令牌通过远程服务器进行身份验证的 HTTP 保护器实现。

注意:由于 API 可能会频繁更改,该软件包处于积极开发中,请参阅更改日志和 README 以了解任何更改。

使用方法

  • 服务提供者

默认情况下,库通过 composer 的 extras 标志构建以注入 laravel 项目的服务提供者。对于 lumen 应用程序,必须手动注册服务提供者类。

// app/bootrap.php

// ...

/*
|--------------------------------------------------------------------------
| Register Service Providers
|--------------------------------------------------------------------------
|
| Here we will register all of the application's service providers which
| are used to bind services into the container. Service providers are
| totally optional, so you are not required to uncomment this line.
|
 */
$app->register(\Drewlabs\HttpGuard\ServiceProvider::class);
  • 配置 Laravel/Lumen 项目的保护器

如果上一节成功完成,http-guard 库将尝试从 auth.php 配置文件加载基本配置。如果缺失,请添加 config/auth.php,并包含以下内容

return [
    // Default values in the auth configuration file
    // ...

    'guards' => [
        // You add other guard drivers
        // ... 
        // Configuration of the http guard driver
        'http' => [
            'driver' => 'http'
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | User Providers
    |--------------------------------------------------------------------------
    |
    | All authentication drivers have a user provider. This defines how the
    | users are actually retrieved out of your database or other storage
    | mechanisms used by this application to persist your user's data.
    |
    | If you have multiple user tables or models you may configure multiple
    | sources which represent each model / table. These sources may then
    | be assigned to any extra authentication guards you have defined.
    |
    | Supported: "database", "eloquent"
    |
    */
    // Here in the providers key of the array, we define the basic configuration that will be loaded by the library service provider at runtime as follow:
    'providers' => [
        // ...
        'http' => [
            // Model class to be used by the package providers
            'model' => \Drewlabs\HttpGuard\User::class,
            // For Http request we must define the endpoint where is located the
            // authorization server(s)
            'hosts' => [
                // When not using a cluster of servers, this default host is used
                'default' => 'https://:4300',

                // Cluster of servers to be used for authentication
                'cluster' => [
                    [
                        'host' => '<HOST_URL>',
                        'primary' => true, // Boolean value indicating whether the host should be query first as primary node
                    ]
                ]
            ]
        ]
    ],
  
    // ...

];

注意:在上面的配置文件中,我们定义了软件包在 Laravel 项目中正常运行所需的基本配置。

  • 定义 http 保护器作为默认保护器

如果在具有多个保护提供者的环境中运行,如 Laravel 框架中,开发者应记住在 auth.php 配置文件中将 http 保护器添加为默认保护器。

// auth.php

// ...
return [
    // ..
    /*
    |--------------------------------------------------------------------------
    | Authentication Defaults
    |--------------------------------------------------------------------------
    |
    | This option controls the default authentication "guard" and password
    | reset options for your application. You may change these defaults
    | as required, but they're a perfect start for most applications.
    |
    */

    'defaults' => [
        'guard' => 'http',
    ],

    // ...
];
  • 添加保护中间件

Laravel 随附一个安全中间件,可以保护路由免受未经授权用户的侵害。由于 Laravel 设置使用保护器,并且 http-guard 是为了支持 Laravel 安全系统而构建的,因此如果正确完成上述配置,开发者可以使用 Laravel 应用程序中随附的默认中间件。

但对于那些想要创建自己的中间件的人来说,这里有一个示例实现

// app/Http/Middleware.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;
use Illuminate\Contracts\Auth\Factory as Auth;

class Authenticate
{


    /**
     * @var Factory
     */
    protected $auth;

    /**
     * Create a new BaseMiddleware instance.
     *
     * @param Auth $auth
     */
    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
    }


    /**
     * Handle an incoming request.
     *
     * @param  Request  $request
     * @param  \Closure  $next
     * @param  string[]  ...$guards
     * @return mixed
     *
     */
    public function handle($request, Closure $next, ...$guards)
    {
        $this->authenticate($guards);
        return $next($request);
    }

    /**
     * Determine if the user is ged in to any of the given guards.
     *
     * @param  array  $guards
     * @return void
     *
     * @throws AuthenticationException
     */
    protected function authenticate(array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }
        // To authenticate users, loop through all the guards provided as parameter
        // to the middleware and check if users are authenticated
        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                return $this->auth->shouldUse($guard);
            }
        }
        $this->unauthenticated($guards);
    }

    /**
     * Handle an unauthenticated user.
     *
     * @param  array  $guards
     * @return void
     *
     * @throws AuthenticationException
     */
    protected function unauthenticated(array $guards)
    {
        throw new AuthenticationException('Unauthenticated.', $guards);
    }
}
  • 注册中间件

对于 Laravel 应用程序,中间件必须在 app/Http/Kernel.php 文件中注册,如下所示

// app/Http/Kernel.php

class Kernel extends HttpKernel {

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        // ...
        'auth' => \App\Http\Middleware\Authenticate::class,
    ];

    // ...
}

对于 Lumen 应用程序

// app/bootstrap.php

// ...

/*
|--------------------------------------------------------------------------
| Register Middleware
|--------------------------------------------------------------------------
|
| Next, we will register the middleware with the application. These can
| be global middleware that run before and after each request into a
| route or middleware that'll be assigned to some specific routes.
|
 */

$app = $app->routeMiddleware([
        // ...
        'auth' => \App\Http\Middleware\Authenticate::class,
]);
  • 缓存

缓存是每个应用程序的重要方面,因此 http-guard 提供了一种机制,即使身份验证或授权服务器关闭,也可以验证用户令牌。

当授权服务器关闭时,http-guard 库将尝试从该缓存提供者加载用户,并验证令牌的发行日期是否仍然有效。如果令牌的发行日期仍然有效,则用户被认为是授权访问应用程序资源的,否则保护器将用户标记为未经授权。

因此,http-guard 库提供了各种缓存系统,使用数组存储(具有文件转储器的内存中存储)、memcached 服务器存储和 Redis 存储。当运行 laravellumen 应用程序时,从 config/database.php 加载 memcached 服务器的配置。否则,必须手动定义配置。

注意:库使用静态类属性用于配置值,因此在手动定义配置值时,请记住将操作集中化,以便在每个请求中运行一次。

以下示例定义用于 AuthServiceProvider 类的配置值,适用于 laravel / lumen 应用程序

// app/Providers/AuthServiceProvider.php

class AuthServiceProvider extends ServiceProvider
{
    // ...

    /**
     * Boot the authentication services for the application.
     *
     * @return void
     */
    public function boot()
    {
        // Configure the Http-Guard library to use cache
        \Drewlabs\HttpGuard\HttpGuardGlobals::usesCache(true);
        // Configure the http-guard library to use PHP 'memcached' storage as default driver
        \Drewlabs\HttpGuard\HttpGuardGlobals::useCacheDriver('memcached');
        // ...
    }
}

使用 Redis 作为缓存驱动器

如前所述,库提供了一个依赖 predis/predis 库的 Redis 存储提供者。为了使用 Redis 存储提供者,开发者必须手动安装 predis/predis。如果在 composer 环境中运行(推荐),可以按以下方式安装库

composer require predis/predis

接下来您需要按照以下步骤配置库以使用redis作为缓存提供者

    // Configure the Http-Guard library to use cache
    \Drewlabs\HttpGuard\HttpGuardGlobals::usesCache(true);
    // Configure the http-guard library to use redis storage as default driver
    \Drewlabs\HttpGuard\HttpGuardGlobals::useCacheDriver('redis');

    // Define the redis connection configuration as defined in predis documentation
    \Drewlabs\HttpGuard\HttpGuardGlobals::forRedis([
            'scheme' => 'tcp',
            'host'   => '10.0.0.1',
            'port'   => 6379,
    ]);
    // ...

注意:Predis文档可以在以下链接找到 [https://github.com/predis/predis]

  • 认证服务器集群

如果您的平台配置支持多个服务器进行认证,请在config/auth.php[providers[http][hosts][cluster]]映射条目中声明集群列表。

注意:在运行集群时,开发者必须提供一个后台任务,定期调用[\Drewlabs\HttpGuard\AuthServerNodesChecker::setAvailableNode()]来更新集群中的可用节点。

  • 自定义

-- 身份认证Web服务路由

默认情况下,保护实现期望身份认证Web服务提供api/v2/userapi/v2/logout作为路由来解析连接用户和撤销认证令牌。但开发者可以通过以下方式自定义此行为

// app/AuthServiceProvider.php

use Drewlabs\HttpGuard\HttpGuardGlobals;

class AuthServiceProvider extends ServiceProvider
{
    // ...
    public function boot()
    {
        // ...
        HttpGuardGlobals::userPath('auth/v2/user'); // Set the api prefix to equal auth instead of api
        HttpGuardGlobals::revokePath('auth/v2/logout');
    }
}

-- 保护名称

默认情况下,库假定配置的保护名称是http。根据应用约束,开发者可能决定全局自定义保护名称。要更改默认行为

// app/AuthServiceProvider.php

use Drewlabs\HttpGuard\HttpGuardGlobals;

class AuthServiceProvider extends ServiceProvider
{
    // ...
    public function boot()
    {
        // ...
        HttpGuardGlobals::guard('api'); // Defines the guard name to be used by the library as `api`
    }
}

-- 用户工厂

从请求响应中构建用户实例并验证所需输入可能是一项繁琐的任务。因此,库提供了一个默认的用户工厂类,该类从请求响应体中构建Drewlabs\Contracts\Auth\Authenticatable::class\Illuminate\Contracts\Auth\Authenticatable::class的实例。但默认工厂类可以被覆盖,方法是将\Drewlabs\HttpGuard\Contracts\UserFactory绑定到容器中,或通过全局定义用户工厂类。

// app/AuthServiceProvider.php

use Drewlabs\HttpGuard\Contracts\UserFactory;

class AuthServiceProvider extends ServiceProvider
{
    // ...
    public function register()
    {
        // ...
        // Defining the user factory
        $this->app->bind(UserFactory::class, function() {
            return function(array $attributes = [], ?string $token = null) {
                // Creates the instance of Authenticatable class
                return $user;
            };
        });
    }
}

或在auth.php

return [
    // Default values in the auth configuration file
    // ...

    'guards' => [
        // You add other guard drivers
        // ... 
        // Configuration of the http guard driver
        'http' => [
            'driver' => 'http'
        ],
    ],
    // ....
    'providers' => [
        // ...
        'http' => [
            // ...
            // Using a class : Uncomment the code below to use the class
            // 'userFactory' => \App\UserFactory::class,
            // Using a closure
            'userFactory' => function(array $attributes = [], ?string $token = null) {
              
            }
        ]
    ],
];