如何在 Laravel 5.4 中添加自定义用户提供程序

Posted

技术标签:

【中文标题】如何在 Laravel 5.4 中添加自定义用户提供程序【英文标题】:How to add a custom User Provider in Laravel 5.4 【发布时间】:2017-12-14 22:03:16 【问题描述】:

我有一个 Laravel 5.4 应用程序,我必须从外部 API 对我的管理员用户进行身份验证,当成功登录时,它会返回一个带有用户信息的 JSON。

我正在创建一个自定义守卫来做到这一点:

    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users'
        ],

        'custom' => [
            'driver' => 'session',
            'provider' => 'customusers'
        ],

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

这是我的自定义提供者:

'providers' => [
    'users' => [
        'driver' => 'eloquent',
        'model' => App\User::class,
    ],

    'customusers' => [
        'driver' => 'jsonresponse',
        'model' => App\Admin::class,
    ]
],

在那之后,我不知道如何继续。我已经阅读了一些类似the one from George Buckingham 的教程,并且我创建了一个自定义用户提供程序(现在我只需要它从 EloquentUserProvider 扩展,最终我将重写一些函数来连接到 API)

<?php

namespace App\Providers;

use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Support\Str;

class CustomUserProvider extends EloquentUserProvider  


然后在 App\Providers\AuthServiceProvider 中注册它

public function boot()

    $this->registerPolicies();

    Auth::provider('jsonresponse', function($app, array $config) 
        return new CustomUserProvider($app['hash'], $config['model']);
    );

在 config/app.php 中

'providers' => [

    // Lots of other providers

    // Own providers
    App\Providers\CustomUserProvider::class,
],

但在那之后,我收到以下错误:

参数 1 传递给 Illuminate\Auth\EloquentUserProvider::__construct() 必须是 Illuminate\Contracts\Hashing\Hasher 的实例, Illuminate\Foundation\Application 给定,调用 /var/www/public/iberorides/vendor/laravel/framework/src/Illuminate/Foundation/Application.php 在第 612 行并定义

如果我重写我的 CustomUserProvider 的构造函数并更改 AuthServiceProvider 中的闭包中的参数,我会收到以下错误:

参数 1 传递给 Illuminate\Foundation\Application::bootProvider() 必须是 Illuminate\Support\ServiceProvider 的实例, App\Providers\IberoUserProvider 给定,调用 /var/www/public/iberorides/vendor/laravel/framework/src/Illuminate/Foundation/Application.php 在第 771 行并定义

这让我觉得我做事的方式不对。

有人能把我引向正确的方向吗?

非常感谢。

【问题讨论】:

【参考方案1】:

解决方案很简单。

首先,不管其他教程怎么说,您不必在配置提供程序中注册CustomUserProvider(此处为 Laravel 5.4)。这就是我遇到错误的原因。

我只需要覆盖 EloquentUserProvider 中的两个方法,retrieveByCredentials(array $credentials) 将根据提供的凭据返回模型,validateCredentials(UserContract $user, array $credentials) 根据凭据是否正确返回布尔值。

您可以将同一个自定义提供程序类与许多提供程序一起使用,而不仅仅是一个,例如

'providers' => [
    'customusers' => [
        'driver' => 'jsonresponse',
        'model' => App\User::class,
    ],

    'customadmins' => [
        'driver' => 'jsonresponse',
        'model' => App\Admin::class,
    ],
],

之后,当您需要检查任何提供者的身份验证时,您需要提供提供者作为保护,例如Auth::guard('customusers').

【讨论】:

谢谢!我尝试为您的解决方案中的类似问题创建分步答案:***.com/a/46224576/2056125 嘿!我真的是新构建 laravel 应用程序,我正在处理类似的场景,但我对如何在这些方法中覆盖“retrieveByCredentials”和“validateCredentials”感到困惑,我是否应该对身份验证路由进行 API 调用并从 API 的 Json 响应构建用户模型?提前致谢! @JuniorSilva 乐于助人。你为什么不问这个问题,这样我就可以在那里回答? @Bul Ikana,我刚刚问了一个问题,如果你能帮我,我会很高兴的!提前致谢!【参考方案2】:

正如@Mark Ba​​aijens 所说

在你的AuthServiceProvider

public function boot()
    
        $this->registerPolicies();

        Auth::provider('eloquent', function($app, array $config) 
            return new class ($app['hash'], $config['model']) extends EloquentUserProvider 

                public function retrieveById($identifier)
                
                    $model = $this->createModel();

                    $condition = [$model->getAuthIdentifierName() => $identifier];


                    if ($model instanceof User) 
                        $condition['custom_more_filed'] = 1;
                    

                    return $model->newQuery()
                                 ->where($condition)
                                 ->first();
                
            ;
        );
    

【讨论】:

【参考方案3】:

如果它对寻找自定义retrieveByCredentials 方法的其他人有任何帮助,可以在不实现自定义UserProvider 的情况下这样做。 EloquentUserProvider 只需要一个凭证数组,并使用数组中每个键/值对的 where 子句构建一个 User 查询。因此,如果您已经有一个定义这些凭据的类,您可以简单地在那里进行自定义。

就我而言,我有一个实现 ResetsPasswordsResetPasswordController。我希望修改在提交期间如何选择用户(使用 ID 和密码,而不是电子邮件和密码),所以我覆盖了 credentials 方法,将 email 替换为 ID_Contact 像这样:

/**
 * Get the password reset credentials from the request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return array
 */
protected function credentials(Request $request)

    return $request->only(
        'password',
        'password_confirmation',
        'token',
        'ID_Contact'
    );

ResetsPasswords 实现中还有其他地方需要自定义,以便将我的特定用例付诸实践(加上密码重置表单本身)。采用这种方法时,每种情况都会有所不同。但这可能会指出一些有用的方向,具体取决于您的特定要求。

【讨论】:

【参考方案4】:

可以通过 AuthServiceProvider 的 boot 方法中的以下代码对 EloquentUserProvider 进行非常小的自定义。

Auth::provider('eloquent', function($app, array $config)

  return new class($app['hash'], $config['model']) extends \Illuminate\Auth\EloquentUserProvider
  

  ;
);

【讨论】:

【参考方案5】:

我发现没有一个解决方案对我很有效,所以我想出了一个超级简单的方法。 (Laravel 5.4)

我的问题是我必须允许用户也使用他们的电话号码登录。

我覆盖了EloquentUserProvider

class PhoneUserProvider extends EloquentUserProvider

    public function retrieveByCredentials(array $credentials)
    
        if (!$credentials) 
            return null;
        

        // Fallback to original email authorization
        if (filter_var($credentials['email'], FILTER_VALIDATE_EMAIL)) 
            return parent::retrieveByCredentials($credentials);
        

        // Assume we are logging in with a phone number
        return UserModel::where('phone', $credentials['email'])->first();
    

在我的AppServiceProvider 引导方法中,我添加了以下几行:

Auth::setProvider(new PhoneUserProvider(app(Hasher::class), UserModel::class));

您甚至可以根据某些条件等在登录控制器中设置提供程序。

【讨论】:

您能否提供指向“要点”或“博客文章”的链接,说明如何正确使用这种方法。 没有更多内容了。你被困在哪里了? 1. 创建一个扩展 EloquentUserProvier 的自定义类 2. 通过调用 Auth::setProvider.. 注册您的用户提供程序以用作身份验证提供程序

以上是关于如何在 Laravel 5.4 中添加自定义用户提供程序的主要内容,如果未能解决你的问题,请参考以下文章

无法在工匠自定义命令 Laravel 5.4 中获取模型关系

Laravel 5.4 登录后重定向到自定义 url

Laravel 5.4 Auth Guardian 驱动程序 [customers] 未定义

Laravel 5.4 - 如何覆盖包中定义的路由?

Laravel 5.4 如何通过表单请求为用户分配角色?

在 Laravel 5.4 中自定义忘记密码的电子邮件