raid/guardian

v1.1.0 2024-09-27 12:23 UTC

This package is auto-updated.

Last update: 2024-09-27 12:47:15 UTC


README

此包是 Laravel Sanctum 包的包装器。[Laravel Sanctum] 它引入了新的概念到认证流程中,例如

要求

  • php >= 8.2
  • laravel/sanctum >= 4.0

安装

composer require raid/guardian

配置

通过运行以下命令将配置文件发布到您的项目

php artisan vendor:publish --provider="Raid\Guardian\Providers\GuardianServiceProvider"

用法

让我们看看使用此包进行认证的基本用法。

class LoginController extends Controller
{
    public function __invoke(Request $request, UserGuardian $guardian)
    {
        $authenticator = $guardian->attempt($request->only([
            'email', 'password',
        ]));

        return response()->json([
            'authenticator' => $authenticator->getName(),
            'token' => $authenticator->getStringToken(),
            'resource' => $authenticator->getAuthenticatable(),
            'errors' => $authenticator->errors()->toArray(),
        ]);
    }
}

Guardian 将处理认证过程,并返回一个包含认证信息的 Authenticator 实例。

Guardian 类定义了将被用于查找用户的 Authenticatable 类,它还定义了用于认证用户的 Authenticators

Authenticator 类依赖于 Matchers 来查找已认证的用户,然后它可以运行一些 NormsSequences 来完成认证过程。

让我们深入了解 AuthenticatableGuardianAuthenticator 类。

可认证的

Authenticates 类将用于查找用户,并在找到时返回 Illuminate\Contracts\Auth\Authenticatable 实例。

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\Authenticatable;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Foundation\Auth\User as IlluminateUser;
use Raid\Guardian\Authenticatable\Contracts\AuthenticatableInterface;

class User extends IlluminateUser implements AuthenticatableInterface
{
    use HasApiTokens;

    public function findForAuthentication(string $attribute, mixed $value): ?AuthenticatableInterface
    {
        return $this->where($attribute, $value)->first();
    }
}

Authenticatable 类必须实现 AuthenticatableInterface 接口。

Authenticatable 类必须定义 findForAuthentication 方法。

findForAuthentication 方法接受两个参数:$attribute$value,这两个参数从提供的凭证中传递。

findForAuthentication 方法必须返回找到的 Illuminate\Contracts\Auth\Authenticatable 实例。

Guardian

Guardian 类将用于定义 Authenticatable 类和 Authenticators,以便通过不同的流程处理认证。

您可以使用以下命令创建一个新的 guardian 类

php artisan raid:make-guardian UserGuardian

这将输出以下代码

<?php

namespace App\Http\Authentication\Guardians;

use Raid\Guardian\Guardians\Guardian;
use Raid\Guardian\Guardians\Contracts\GuardianInterface;

class UserGuardian extends Guardian implements GuardianInterface
{
    public const NAME = '';

    protected string $authenticatable;

    protected array $authenticators = [];
}

让我们配置 Guardian 类。

<?php

namespace App\Http\Authentication\Guardians;

use App\Models\User;
use App\Http\Authentication\Guardians\SystemAuthenticator;
use Raid\Guardian\Guardians\Guardian;
use Raid\Guardian\Guardians\Contracts\GuardianInterface;

class UserGuardian extends Guardian implements GuardianInterface
{
    public const NAME = 'user';

    protected string $authenticatable = User::class;

    protected array $authenticators = [
        SystemAuthenticator::class,
    ];
}

Guardian 类必须实现 GuardianInterface

Guardian 类必须扩展 Guardian 类。

Guardian 类应该定义 name 常量。

Guardian 类必须定义 authenticatable 属性。

Guardian 类应该定义 authenticators 属性。

Guardian 类可以处理其定义的任何 authenticators 的认证。

您可以使用两种方式定义 authenticators

  • authenticators 属性
  • config\authentication.php 文件
<?php

use App\Http\Authentication\Guardians\UserGuardian;
use App\Http\Authentication\Authenticators\SystemAuthenticator;

return [

    'guardian_authenticators' => [
        UserGuardian::class => [
            SystemAuthenticator::class,
        ],
    ],
];

此定义允许您使用认证器名称通过不同的 Authenticators 认证用户。

如果您没有传递任何认证器,则将使用默认认证器。

<?php

class LoginController extends Controller
{
    public function __invoke(Request $request, UserGuardian $guardian)
    {
        $credentials = $request->only([
            'email', 'password',
        ]);
        
        $authenticator = $guardian->attempt($credentials, 'system');
    }
}

认证器

Authenticator 类将用于使用传递的 Authenticatable 类和 Credentials 处理认证过程。

您可以使用以下命令创建一个新的认证器类

php artisan raid:make-authenticator SystemAuthenticator

这将输出以下代码

<?php

namespace App\Http\Authentication\Authenticators;

use Raid\Guardian\Authenticators\Authenticator;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;

class SystemAuthenticator extends Authenticator implements AuthenticatorInterface
{
    public const NAME = '';
}

让我们配置 Authenticator 类。

<?php

namespace App\Http\Authentication\Authenticators;

use Raid\Guardian\Authenticators\Authenticator;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;

class SystemAuthenticator extends Authenticator implements AuthenticatorInterface
{
    public const NAME = 'system';
}

Authenticator 类必须实现 AuthenticatorInterface

Authenticator 类必须扩展 Authenticator 类。

Authenticator 类应该定义 name 常量。

Authenticator 通过 Matchers 工作来查找已认证的用户,它将定义的 Matchers 属性与给定的凭证匹配。

<?php

namespace App\Http\Authentication\Authenticators;

use App\Http\Authentication\Matchers\EmailMatcher;
use Raid\Guardian\Authenticators\Authenticator;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;

class SystemAuthenticator extends Authenticator implements AuthenticatorInterface
{
    public const NAME = 'system';
    
    protected array $matchers = [
        EmailMatcher::class,
    ];
}

您可以使用两种方式来定义matchers

  • matchers属性
  • config\authentication.php 文件
<?php

use App\Http\Authentication\Authenticators\SystemAuthenticator;
use App\Http\Authentication\Matchers\EmailMatcher;

return [

    'authenticator_matchers' => [
        SystemAuthenticator::class => [
            EmailMatcher::class,
        ],
    ],
];

这种定义允许您使用定义的属性通过不同的Matchers进行用户认证。

Matcher

Matcher类将用于根据给定的凭据找到已认证的用户。

您可以使用此命令创建一个新的matcher类

php artisan raid:make-matcher EmailMatcher

这将输出以下代码

<?php

namespace App\Http\Authentication\Matchers;

use Raid\Guardian\Matchers\Matcher;
use Raid\Guardian\Matchers\Contracts\MatcherInterface;

class EmailMatcher extends Matcher implements MatcherInterface
{
    public const ATTRIBUTE = '';
}

让我们配置Matcher类。

<?php

namespace App\Http\Authentication\Matchers;

use Raid\Guardian\Matchers\Matcher;
use Raid\Guardian\Matchers\Contracts\MatcherInterface;

class EmailMatcher extends Matcher implements MatcherInterface
{
    public const ATTRIBUTE = 'email';
}

Matcher类必须实现MatcherInterface

Matcher类必须扩展Matcher类。

Matcher类必须定义ATTRIBUTE常量。

Matcher还可以定义一个QUERY_ATTRIBUTE常量来查找用户。

ATTRIBUTE用于将Matcher与给定的凭据匹配。

QUERY_ATTRIBUTE被传递给findForAuthentication方法以查找用户,如果未定义,则将使用ATTRIBUTE常量。

Norm

Norm类将用于验证认证。

要应用Norms,您需要将ShouldRunNorms接口实现到Authenticator类,然后您可以定义您的Norms

<?php

namespace App\Http\Authentication\Authenticators;

use App\Http\Authentication\Norms\VerifiedNorm;
use Raid\Guardian\Authenticators\Authenticator;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Authenticators\Contracts\ShouldRunNorms;

class SystemAuthenticator extends Authenticator implements AuthenticatorInterface, ShouldRunNorms
{
    public const NAME = 'system';
    
    protected array $norms = [
        VerifiedNorm::class,    
    ];
}

您可以使用两种方式来定义norms

  • norms属性
  • config\authentication.php 文件
use App\Http\Authentication\Authenticators\SystemAuthenticator;
use App\Http\Authentication\Norms\VerifiedNorm;

return [
   
    'authenticators_norms' => [
        SystemAuthenticator::class => [
            VerifiedNorm::class,
      ],
];

Norms将被应用于Authenticator以验证认证。

您可以使用此命令创建一个新的规则类

php artisan raid:make-norm VerifiedNorm

这将输出以下代码

<?php

namespace App\Http\Authentication\Norms;

use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Norms\Contracts\NormInterface;

class VerifiedNorm implements NormInterface
{
    public function handle(AuthenticatorInterface $authenticator): bool
    {
    }

    public function fail(AuthenticatorInterface $authenticator): void
    {
    }
}

让我们配置Norm类。

<?php

namespace App\Http\Authentication\Norms;

use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Norms\Contracts\NormInterface;

class VerifiedNorm implements NormInterface
{
    public function handle(AuthenticatorInterface $authenticator): bool
    {
        return $channel->getAuthenticatable()->isVerified();
    }
    
    public function fail(AuthenticatorInterface $authenticator): void
    {
        $channel->fail(message: __('auth.unverified'));
    }
}

Norm类必须实现NormInterface

Norm类必须定义handle方法。

handle方法必须返回一个布尔值。

handle方法将被Authenticator调用以验证认证。

Sequence

Sequence类将用于在认证过程中添加额外的步骤。

要应用Sequences,您需要将ShouldRunSequences接口实现到Authenticator类,然后您可以定义您的Sequences

<?php

namespace App\Http\Authentication\Authenticators;

use App\Http\Authentication\Sequences\TwoFactorEmailSequence;
use Raid\Guardian\Authenticators\Authenticator;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Authenticators\Contracts\ShouldRunSequences;

class SystemAuthenticator extends Authenticator implements AuthenticatorInterface, ShouldRunSequences
{
    public const NAME = 'system';
    
    protected array $sequences = [
        TwoFactorEmailSequence::class,
    ],
}

您可以使用两种方式来定义sequences

  • sequences属性
  • config\authentication.php 文件
<?php

use App\Http\Authentication\Authenticators\SystemAuthenticator;
use App\Http\Authentication\Sequences\TwoFactorEmailSequence;

return [
   
    'authenticators_sequences' => [
        SystemAuthenticator::class => [
            TwoFactorEmailSequence::class,
      ],
];

Sequences将被应用于Authenticator以在认证过程中添加额外的序列。

您可以使用此命令创建一个新的步骤类

php artisan raid:make-sequence TwoFactorEmailSequence

这将输出以下代码

<?php

namespace App\Http\Authentication\Sequences;

use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Sequences\Contracts\SequenceInterface;

class TwoFactorEmailSequence implements SequenceInterface
{
    public function handle(AuthenticatorInterface $authenticator): void
    {
    }
}

让我们配置Sequence类。

<?php

namespace App\Http\Authentication\Sequences;

use App\Core\Integrations\Mail\MailService;
use App\Mail\TwoFactorMail;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Sequences\Contracts\SequenceInterface;

class TwoFactorEmailStep implements SequenceInterface
{
    public function __construct(
        private readonly MailService $mailService,
    ) {

    }

    public function handle(AuthenticatorInterface $authenticator): void
    {
        $code = generate_code();
        
        $authenticatable = $authenticator->getAuthenticatable();

        $authenticatable->update([
            'two_factor_email_code' => $code,
        ]);
        
        $this->send(
            $authenticatable->getAttribute('email'),
            $authenticatable->getAttribute('name'),
            $code,
        );
    }

    private function send(string $email, string $name, int $code): void
    {
        $this->mailService->send(
            $email,
            new TwoFactorMail($name, $code),
        );
    }
}

Sequence必须实现SequenceInterface

Sequence类必须定义handle方法。

handle方法将被Authenticator调用以在认证过程中添加额外的序列。

提示:运行任何步骤意味着Authenticator将停止认证过程而不会发出任何令牌,此方法可用于多因素认证。

您可以将您的序列类配置为通过队列工作。

<?php

namespace App\Http\Authentication\Sequences;

use App\Mail\TwoFactorMail;
use App\Core\Integrations\Mail\MailService;
use Raid\Guardian\Authenticators\Contracts\AuthenticatorInterface;
use Raid\Guardian\Sequences\Contracts\QueueSequenceInterface;

class TwoFactorEmailSequence implements QueueSequenceInterface
{
    use HasQueue;

    public function __construct(
        private readonly MailService $mailService,
    ) {

    }

    public function handle(AuthenticatorInterface $authenticator): void
    {
        $code = generate_code();
        
        $authenticatable = $authenticator->getAuthenticatable();

        $authenticatable->update([
            'two_factor_email_code' => $code,
        ]);
        
        $this->send(
            $authenticatable->getAttribute('email'),
            $authenticatable->getAttribute('name'),
            $code,
        );
    }

    private function send(string $email, string $name, int $code): void
    {
        $this->mailService->send(
            $email,
            new TwoFactorMail($name, $code),
        );
    }
}

队列序列必须实现QueueSequenceInterface

队列序列类必须定义queue方法。

您可以使用HasQueue特性行为定义带有默认配置的queue方法。

您可以通过定义以下方法来覆盖特性行为的队列配置

protected function getJob(): string
{
    // return your Job class;
}

protected function getConnection(): ?string
{
    // return your Connection name;
}

protected function getQueue(): ?string
{
    // return your Queue name;
}

protected function getDelay(): DateInterval|DateTimeInterface|int|null
{
    // return your Delay interval;
}

认证器错误

您可以使用Authenticator类通过errors方法处理认证错误。

您可以使用这些方法向认证器添加错误

$authenticator->fail('key', 'message');
// or
$authenticator->errors()->add('key', 'message');

您可以使用这些方法检查认证器错误

$hasErrors = $authenticator->failed();
//or
$hasErrors = $authenticator->errors()->any();

$hasError = $authenticator->errors()->has('key');

$errorsByKey = $authenticator->errors()->get('key');

$firstError = $authenticator->errors()->first();

$lastError = $authenticator->errors()->last();

$errorsAsArray = $authenticator->errors()->toArray();

$errorsAsJson = $authenticator->errors()->toJson();

就这些了。

许可

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

鸣谢

安全

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

关于Raid

RAID 是由 Mohamed Khedr 创建的 PHP 框架,并由 Mohamed Khedr 维护。

支持 RAID

RAID 是一个 MIT 许可的开源项目。这是一个独立项目,其持续发展得以实现。