abublihi/laravel-external-jwt-guard

这是一个使用外部JWT进行用户身份验证的Laravel自定义认证保护器

v3.0.1 2024-09-11 11:46 UTC

README

Latest Version on Packagist Total Downloads Tests

此包提供了一个简单的自定义认证保护器,用于Laravel,使用由OAuth服务器提供的或任何使用JWT的任何类型的SSO提供的JWT。以下图表示明了流程。

安装

您可以通过composer安装此包

composer require abublihi/laravel-external-jwt-guard

发布配置文件 externaljwtguard.php

php artisan vendor:publish --provider="Abublihi\LaravelExternalJwtGuard\LaravelExternalJwtGuardServiceProvider" --tag config

使用方法

此包非常简单,但在定制方面也非常强大。在安装和发布配置之后,您首先需要配置您的 default 授权服务器,

注意:此包允许您添加多个授权服务器,但对于大多数使用场景,您只需要一个授权服务器。

配置您的授权服务器

<?php

return [
    'authorization_servers' => [
        'default' => [
            /* Identification settings */
            'id_claim' => env('JWT_GUARD_ID_CLAIM', 'sub'),
            'roles_claim' => env('JWT_GUARD_ROLES_CLAIM', 'roles'),
            'id_attribute' => env('JWT_GUARD_ID_ATTRIBUTE', 'id'),

            /* Creation setting */
            'create_user' =>  env('JWT_GUARD_CREATE_USER', false),
            'create_user_action_class' => null,
            
            /* Validation settings */
            'issuer' => '',
            'validate_issuer' => true,
            'public_key' => env('JWT_GUARD_AUTH_SERVER_PUBLIC_KEY'), // if RSA, make sure it's start with -----BEGIN PUBLIC KEY----- and ends with -----END PUBLIC KEY-----
            'signing_algorithm' => env('JWT_GUARD_AUTH_SIGN_ALG', 'RS256'),
        ],
        // you could add as many as you want of the authorization servers by duplicating the configurations above ^^
        'admin' => [ 'id_claim' => 'sub', ..... ]
    ],
];

请访问配置文件 config/externaljwtguard.php,配置分为三个主要部分

  • 身份设置
  • 创建设置(可选)
  • 验证设置

身份设置

首先我们将介绍 身份设置 的配置,正如其名,身份设置 是允许此包通过使用JWT声明来识别用户的配置。

注意:请确保这些配置正确。

注意:id_attribute是您的系统中的,此包使用它来识别已认证的用户,例如,如果您已将保护器配置为配置了用户模型的提供者,则此包将查找id_attribute并将其与JWT中的id_claim进行匹配

'id_claim' => env('JWT_GUARD_ID_CLAIM', 'sub'),
'roles_claim' => env('JWT_GUARD_ROLES_CLAIM', 'roles'), // not yet used
'id_attribute' => env('JWT_GUARD_ID_ATTRIBUTE', 'id'), // in your database (e.g. users table)

创建设置(可选)

创建设置用于配置如果系统不存在时如何创建用户,您可以禁用此功能,我们鼓励禁用此功能。

注意:您必须自己实现创建用户的操作,该操作应实现接口 Abublihi\LaravelExternalJwtGuard\Interfaces\CreateUserActionInterface

'create_user' =>  env('JWT_GUARD_CREATE_USER', false),
// you can define your own action by implementing the interface Abublihi\LaravelExternalJwtGuard\Interfaces\CreateUserActionInterface
'create_user_action_class' => null,

验证设置

'issuer' => 'https://example.com',
'validate_issuer' => true,
'public_key' => env('JWT_GUARD_AUTH_SERVER_PUBLIC_KEY'), // if RSA, make sure it's start with -----BEGIN PUBLIC KEY----- and ends with -----END PUBLIC KEY-----
'signing_algorithm' => env('JWT_GUARD_AUTH_SIGN_ALG', 'RS256'),

保护器配置

在配置我们的授权服务器后,接下来我们需要在 config/auth.php 中配置我们的保护器

在Guards中,您可以添加/修改您想要使用JWT作为认证保护器的保护器,通过将驱动设置为 external-jwt-auth。我们有一个自定义属性,即 auth_server_key,它指示授权服务器密钥,默认设置为 default

'guards' => [
    .
    .
    'api-jwt' => [
        'driver' => 'external-jwt-auth', // <-- here you have to set the drive to `external-jwt-auth`
        'provider' => 'users',
    ],
    
    // you can set the authorization server key as seen below 
    'api-jwt-admin' => [
        'driver' => 'external-jwt-auth', // <-- here you have to set the drive to `external-jwt-auth`
        'provider' => 'users',
        'auth_server_key' => 'admin', // the authorization key for admin 
    ],
    .
    .
],

测试您的配置

在例如 routes/api.php 中添加路由

Route::middleware('auth:api-jwt')->group(function() {
    Route::get('user', function(){
        return request()->user(); // <-- will return the user which is configured
    });
});

JWT角色中间件

此包还附带一个检查JWT(用户)角色的角色中间件,您应首先使用配置文件 roles_claim 配置正确的角色声明,该声明应是一个 数组 的角色。要使用中间件,您有两个选项

  1. app/Http/Kernel.php 中定义一个 别名
  2. 直接使用中间件而不使用别名

在kernel中定义中间件别名

转到 app/Http/Kernel.php 并添加以下行

注意:别名名称可以是任何名称

protected $middlewareAliases = [
    // ...
    'jwt-role' => \Abublihi\LaravelExternalJwtGuard\Middleware\CheckJwtRoles::class
];

在路由中使用中间件

Route::group(['middleware' => ['auth:api-jwt' 'jwt-role:manager']], function () {
    // this will allow any jwt with the role `manager`
});

您可以使用 |(管道)字符指定多个角色,该字符被视为 OR

Route::group(['middleware' => ['auth:api-jwt' 'jwt-role:manager|super-admin']], function () {
    // this will allow any jwt with the role `manager` or `super-admin`
});

直接在kernel上使用中间件而不定义它

use Abublihi\LaravelExternalJwtGuard\Middleware\CheckJwtRoles;

Route::group(['middleware' => ['auth:api-jwt' CheckJwtRoles::class.':manager']], function () {
    // this will allow any jwt with the role `manager`
});

您可以使用 |(管道)字符指定多个角色,该字符被视为 OR

// with OR operator 
Route::group(['middleware' => ['auth:api-jwt' CheckJwtRoles::class.':manager|super-admin']], function () {
    // this will allow any jwt with the role `manager`
});

示例JWT与角色声明

{
  "iss": "http://example.com",
  "aud": "http://example.org",
  "sub": "2",
  "jti": "4f1g23a12aa",
  "iat": 1707071173.863238,
  "nbf": 1707071113.863238,
  "exp": 1707074773.863238,
  "uid": "2",
  "roles": [
    "manager",
    "super-admin"
  ]
}

测试

ActingAs 功能

本包提供actingAs函数,帮助您测试受external-jwt-auth守卫保护的路由,要使用它,只需在测试中使用\Abublihi\LaravelExternalJwtGuard\Traits\ActingAs特性,然后调用actingAsExternalJwt函数,这将生成配置(私有和公开密钥)和有效的令牌,然后使用$this->withHeader(..)将其添加到请求头。

class SampleTest extends TestCase
{
    use DatabaseMigrations, \Abublihi\LaravelExternalJwtGuard\Traits\ActingAs;

    /**
     * @test
     * @define-route usesAuthRoutes
     */
    function test_it_returns_authenticated_user_by_jwt()
    {
        $user = User::factory()->create();

        $this->actingAsExternalJwt($user);
    }
}

如果您想生成带有一些自定义声明或无效或过期的令牌,可以将Abublihi\LaravelExternalJwtGuard\Support\FakeTokenIssuer实例传递给actingAsExternalJwt

如果您想生成无效或过期的令牌,例如,可以将Abublihi\LaravelExternalJwtGuard\Support\FakeTokenIssuer实例传递给actingAsExternalJwt

use Abublihi\LaravelExternalJwtGuard\Support\FakeTokenIssuer;

class SampleTest extends TestCase
{
    use DatabaseMigrations, \Abublihi\LaravelExternalJwtGuard\Traits\ActingAs;

    /**
     * @test
     * @define-route usesAuthRoutes
     */
    function test_it_returns_authenticated_when_with_role_admin()
    {
        $user = User::factory()->create();

        $this->actingAsExternalJwt(
            FakeTokenIssuer:user($user)
                ->withClaims([
                    'roles' => [
                        'admin'
                    ]
                ])
        );
    }

    /**
     * @test
     * @define-route usesAuthRoutes
     */
    function test_it_returns_authenticated_when_with_custom_claim_employee_name()
    {
        $user = User::factory()->create();

        $this->actingAsExternalJwt(
            FakeTokenIssuer:user($user)
                ->withClaims([
                    'employee_name' => 'Mohammed Abdullah',
                    'other_info' => [
                        'info 1',
                        'info 2'
                    ]
                ])
        );
    }

    /**
     * @test
     * @define-route usesAuthRoutes
     */
    function test_it_returns_unauthenticated_when_invaild()
    {
        $user = User::factory()->create();

        $this->actingAsExternalJwt(
            FakeTokenIssuer:user($user)
                ->asInvalid()
        );
    }
 
    /**
     * @test
     * @define-route usesAuthRoutes
     */
    function test_it_returns_unauthenticated_when_expired()
    {
        $user = User::factory()->create();

        $this->actingAsExternalJwt(
            FakeTokenIssuer:user($user)
                ->asExpired()
        );
    }
}

生成的代码和配置将设置为default授权服务器,您可以通过传递授权服务器密钥给第二个参数来更改它。

class SampleTest extends TestCase
{
    use DatabaseMigrations, \Abublihi\LaravelExternalJwtGuard\Traits\ActingAs;

    /**
     * @test
     * @define-route usesAuthRoutes
     */
    function test_it_returns_authenticated_user_by_jwt()
    {
        $user = User::factory()->create();

        $this->actingAsExternalJwt($user, 'admin'); // this will set the authorization server key to `admin`
    }
}

测试包

composer test

变更日志

有关最近更改的更多信息,请参阅CHANGELOG

贡献

有关详细信息,请参阅CONTRIBUTING

安全性

如果您发现任何与安全相关的问题,请通过电子邮件abublihi@gmail.com而不是使用问题跟踪器。

致谢

许可

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