让用户和客户端共享相同的身份验证

Let Users and Clients share the same authentication

我正在使用 Laravel + Breeze。我的应用程序将有两个访问站点:

  1. 管理员可以登录相关用户table(工作中)
  2. 客户端可以登录相关客户端table(待讨论)

我不知道,这是否是个好主意,但我想与另一个模型:clients 共享已经实现的 Auth 服务。

我已经实现的是:

现在对我来说变得棘手了。 AuthenticatedSessionController::store() 方法正在检查 $request->authenticate(),这会再次对用户 table 运行,但对客户端 table 失败。 我稍微修改了根据登录候选类型重定向的方法:

public function store(LoginRequest $request)
    {
        $request->authenticate();
        
        $request->session()->regenerate();

        $user = User::where('id', Auth::id())->first();
        if ( $user ) {
            return redirect()->intended(RouteServiceProvider::HOME);
        }

        $client = Client::where('id', Auth::id())->findOrFail();
        if ( $client ) {
            return redirect()->to('portal.show', $client->id);
        }
    }

但这仅适用于用户,因为 $request->authenticate() 不会让客户进入。 现在我需要支持,从这里开始我只是猜测下一步是我在 config/auth.php:

中所做的更新
return [
    'defaults' => [
        'guard' => 'web',
        'passwords' => 'users',
    ],
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
    ],
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
        'clients' => [
            'driver' => 'eloquent',
            'model' => App\Models\Client::class,
        ],
    ],
    'passwords' => [
        'users' => [
            'provider' => 'users',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
        'clients' => [
            'provider' => 'clients',
            'table' => 'password_resets',
            'expire' => 60,
            'throttle' => 60,
        ],
    ],
    'password_timeout' => 10800,

];

您需要研究并修改 App\Http\Requests\Auth\LoginRequest class 的 authenticate 方法。

一种方法是检查是否存在通过针对 usersclients table 的请求收到的 email

然后,如果 电子邮件 属于客户端 - 实施自定义逻辑以根据 clients table 记录验证凭据并登录客户端

并且如果 电子邮件 属于用户 - 然后让请求正常通过

例如:

public function authenticate()
{
    $type = DB::table('clients')->where('email', $this->email)->exists() ? 'client' : 'user';

    if($type === 'user') {
        return $this->authenticateUser();
    }

    //Validate credentials against `clients` table 
    // If valid retrieve the client and login the client 
    //Else throw ValidationException
}

//Copy the content of original authenticate to this method
protected function authenticateUser()
{

    $this->ensureIsNotRateLimited();

    if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) {
    RateLimiter::hit($this->throttleKey());

        throw ValidationException::withMessages([
            'email' => trans('auth.failed'),
        ]);
    }

    RateLimiter::clear($this->throttleKey());
}

注意 使用这种方法你不会做任何rate-limiting/throttling也不会触发尝试事件

对于完整的客户端身份验证系统,我想需要定义一个单独的守卫、用户提供者,然后重新定义 re-implement SessionGuard 功能。

想到的另一个疯狂的想法是,为什么不将 Client 表示为 users table 上的记录,仅用于身份验证目的,并且可能它们之间有 one-to-one 关系。