mpyw/null-auth

针对 Laravel 的空值保护。专为基于中间件的认证和测试设计。

v2.1.0 2024-03-13 03:41 UTC

This package is auto-updated.

Last update: 2024-09-13 04:44:25 UTC


README

针对 Laravel 的空值保护。专为基于中间件的认证和测试设计。

要求

  • PHP: ^8.0
  • Laravel: ^9.0 || ^10.0 || ^11.0

安装

composer require mpyw/null-auth

功能

NullAuthenticatable 系列

  • ❗️显示包含抽象方法的。
  • Strict 特性在不良方法调用时抛出 BadMethodCallException

NullGuard

  • NullGuard::user() 总是返回由 NullGuard::setUser() 设置的已认证的用户。
  • NullGuard::unsetUser() 可以取消用户。

NullUserProvider

  • 所有方法都不做任何事情,总是返回假值。

使用方法

基本使用

编辑你的 config/auth.php

<?php

return [

    /* ... */

    /*
    |--------------------------------------------------------------------------
    | Authentication Guards
    |--------------------------------------------------------------------------
    |
    | Next, you may define every authentication guard for your application.
    | Of course, a great default configuration has been defined for you
    | here which uses session storage and the Eloquent user provider.
    |
    | 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.
    |
    | Supported: "session", "token"
    |
    */

    'guards' => [
        'web' => [
            'driver' => 'null', // Use NullGuard for "web"
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | 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"
    |
    */

    'providers' => [
        'users' => [
            'driver' => 'null', // Use NullUserProvider for "users"
        ],
        
        // 'users' => [
        //     'driver' => 'eloquent',
        //     'model' => App\User::class,
        // ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],

    /* ... */
];

动机

基于守卫的 API 认证

考虑向外部平台发送 HTTP 请求的认证。

在这种情况下,你可能通过 RequestGuard 通过 Auth::viaRequest() 调用来使用。然而,某些在合约 UserProviderAuthenticatable 上的方法是不可用的。它们严重依赖于以下流程

  1. 通过电子邮件地址从数据库检索用户
  2. 验证用户的密码散列

此库提供了一个帮助器,使无用的合约方法不执行任何操作;始终返回空值或假值。

现在我们在用户模型上包含 NullAuthenticatable 特性。

<?php

namespace App;

use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Mpyw\NullAuth\NullAuthenticatable;

class User extends Model implements Authenticatable
{
    use NullAuthenticatable;
}

然后只提供有效的实现 getAuthIdentifierName()getAuthIdentifier()

<?php

$user = User::find(1);

// Minimal implementation for Authenticatable
var_dump($user->getAuthIdentifierName()); // string(2) "id"
var_dump($user->getAuthIdentifier());     // int(1)

// Useless implementation for Authenticatable when we don't use StatefulGuard
var_dump($user->getAuthPassword());       // string(0) ""
var_dump($user->getRememberTokenName());  // string(0) ""
var_dump($user->getRememberToken());      // string(0) ""
$user->setRememberToken('...');           // Does nothing

基于中间件的认证

假设你讨厌使用 RequestGuard,并希望在中间件上实现认证。

Auth::user() 之类的调用在每次请求第一次调用时都会产生副作用。如果你将认证集中在中间件上,并仅将 Auth::user() 作为 Authenticatable 对象的容器来使用,这可能会导致不适当的行为。

不用担心。此库提供 NullGuard,这正好是你想要的简单的 Authenticatable 容器。 Auth::user() 不执行任何操作,只返回缓存的 Authenticatable。你只需轻松地在你的酷中间件上调用 Auth::setUser() 即可。

<?php

namespace App\Http\Middleware;

use App\User;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Example\API\Authentication\Client;

class AuthenticateThroughExternalAPI
{
    /**
     * @var \Example\API\Authentication\Client
     */
    protected $client;

    /**
     * @param \Example\API\Authentication\Client $client
     */
    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    /**
     * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // Return user_id on success, throw AuthenticationException on failure
        $userId = $this->client->authenticate($request->input('token'));

        // Return User on success, throw ModelNotFoundException on failure
        $user = User::findOrFail($userId);

        Auth::setUser($user);

        return $next($request);
    }
}

测试

不用说,它也适用于测试。不用担心会产生副作用。