9 个 Laravel Auth 脚手架相关的小技巧

Laravel

Laravel拥有一个很棒的现成的用户认证系统,当然我们也需要在在某些地方自定义一些配置。对于某些自定义配置,我们并不需要再去寻找一个扩展包或者写一大堆代码。让我们来研究一下这套认证系统背后隐藏着哪些有趣的功能。

技巧 1. Auth::routes() 参数

我们应该都知道方法 Auth::routes() 来自于 Laravel UI package (在Laravel 7之前, 它被包含在内核中)。

但你知道它可以接受一个数组来启用/禁用特定的认证路由吗?

对于Laravel 7,下面是可用的参数及其默认值:

Auth::routes([
    'login'    => true, 
    'logout'   => true, 
    'register' => true, 
    'reset'    => true,   // 用于重置密码
    'confirm'  => false,  // 用于额外的密码确认
    'verify'   => false,  // 用于邮箱认证
]);

这些参数仅启用或禁用某些路由。

要了解它们是如何工作的,可以查看文件Laravel UI中的AuthRouteMethods

return function ($options = []) {
    // 登录路由...
    if ($options['login'] ?? true) {
        $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
        $this->post('login', 'Auth\LoginController@login');
    }

    // 登出路由...
    if ($options['logout'] ?? true) {
        $this->post('logout', 'Auth\LoginController@logout')->name('logout');
    }

    // 注册路由...
    if ($options['register'] ?? true) {
        $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
        $this->post('register', 'Auth\RegisterController@register');
    }

    // 密码重设路由...
    if ($options['reset'] ?? true) {
        $this->resetPassword();
    }

    // 密码确认路由...
    if ($options['confirm'] ??
        class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) {
        $this->confirmPassword();
    }

    // 邮箱验证路由...
    if ($options['verify'] ?? false) {
        $this->emailVerification();
    }
};

技巧 2. Laravel UI: 仅生成控制器

官方文档指定了使用 Laravel UI 的主要方法:

php artisan ui vue --auth

但是,如果您不需要可视 UI,该怎么办?如果您创建的是一个仅基于 API 的项目,且在框架中没有任何前端呢?

您仍然可以使用 Laravel Auth 及其控制器。安装 Laravel UI 并运行以下命令:

php artisan ui:controllers

它只会生成 app/Http/Controllers/Auth , 因此您不需要 Blade 或 Vue 文件即可使用它们。

请在 Github 存储库 中参阅这个 Artisan 命令的实现。


技巧 3. 对敏感操作重新认证密码

您是否曾经维护过 Github 存储库,并试图更改其访问设置?然后,Github 要求您再次输入密码,以确保确实是您在操作。

从 Laravel 6.2 开始,框架中也集成了该功能。

Laravel 密码确认

您只需要向要保护的路由添加一个名为password.confirm的中间件即可。

Route::get('/secrets', 'SecretsController@show')->middleware('password.confirm');

Dries Vints 引用自官方功能发布文章

如果尝试访问该路由,将提示您确认密码,和在 GitHub 等其他应用程序上看到的一样。

确认密码后,默认情况下会在用户会话中存储一个时间戳。时间戳持续3个小时,因此用户在此期间不必再次输入密码。

您可以使用auth配置文件中的password_timeout配置选项来自定义此持续时间。


技巧 4. 注销其他设备

从 Laravel 5.6 起,我们提供了一种单独的方法来自动注销使用我们的帐户登录的任何其他设备或浏览器:

Auth::logoutOtherDevices($password); 

典型的用法是在当前设备成功登录后注销其他设备。为此,我们从 TraitAuthenticatesUsers.php中重写方法authenticated(),并将其放入app / Http / Controllers / Auth / LoginController.php中:

protected function authenticated(Request $request, $user)
{
    \Auth::logoutOtherDevices(request('password'));
}

另外,不要忘记激活app / Http / Kernel.php文件中的中间件AuthenticateSession,默认情况下该中间件已被注释:

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

登录/注册后的重定向:自定义逻辑

默认情况下,Laravel 的 LoginController 和 RegisterController 具有相同的属性:

class RegisterController extends Controller
{
    protected $redirectTo = RouteServiceProvider::HOME;

因此,您可以指定成功登录/注册后重定向到的 URL。默认值在 app/Providers/RouteServiceProvider.php中:

class RouteServiceProvider extends ServiceProvider
{
    public const HOME = '/home';

如何自定义它?

首先,您可以分别为登录和注册控制器的$redirectTo属性指定其他值。

但是,如果您具有更复杂的动态重定向逻辑,例如需要根据用户角色来判断呢?

您可以在身份验证控制器中创建一个redirectTo()方法,然后在其中指定条件。该方法将覆盖$ redirectTo属性的任何值。

参见示例:

class RegisterController extends Controller
{
    protected $redirectTo = RouteServiceProvider::HOME;

    protected function redirectTo()
    {
        if (auth()->user()->role_id == 1) {
            return '/admin';
        }
        return '/home';
    }

技巧 5. 快速创建新用户

如果您需要创建一个新用户,但还没有准备好注册页面该怎么办?

只需在您的终端中打开 Laravel Tinker

php artisan tinker

如果您不熟悉 Tinker,需要知道它是能够执行任何 Laravel / PHP 代码的命令行工具。因此,在其中,您可以轻松创建用户,键入此 Eloquent 命令并按 Enter:

\App\User::create(['name' => 'Admin', 'email' => 'admin@admin.com', 'password' => bcrypt('somesecurepassword')]);

但是,如果您需要创建许多用户进行测试,例如10、100或1000,该怎么办?没问题,我们可以在database / factories / UserFactory.php中使用 Laravel 默认提供的 Factory 类:

$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // 密码
        'remember_token' => Str::random(10),
    ];
});

这些是我们创建的“假”用户的默认值。为此,我们将生成一个 Seeder 文件:

php artisan make:seeder UsersSeeder

然后,我们打开生成的文件database / seeds / UsersSeeder.php,并用以下代码填充run()方法:

public function run()
{
    // This will create 100 users
    factory(App\User::class, 100)->create(); 
}

要运行它,我们需要执行以下命令:

php artisan db:seed --class=UsersSeeder

您可以在Laravel官方文档中了解更多有关数据库种子的信息。


Tip 6. 使用邮箱和/或用户名登录

默认情况下,Laravel用户使用邮箱密码进行身份验证。但是,如果您的用户标识不使用邮箱怎么办?例如,使用用户名作为标识。

您可以通过覆盖 traitAuthenticatesUsers.php中的一种方法来轻松更改它。

这是默认值:

trait AuthenticatesUsers
{
    // ... 其他方法

    public function username()
    {
        return 'email';
    }

您可以将其复制到您的LoginController.php中,只需更改值即可:

class LoginController extends Controller
{
    use AuthenticatesUsers;

    // ... 其他方法

    public function username()
    {
        return 'username';
    }
}

让我们更进一步。如果您想让用户可以使用邮箱或用户名登录怎么办?这样的话,用户可以在“邮箱/用户名”字段中选择其中一个填写。

让我们向上面的username()方法添加一个判断。我们检查输入的字符串是否是电子邮件,若不是,则将其视为用户名。这是一个 PHP 函数,甚至不是 Laravel 函数。

class LoginController extends Controller
{
    // ...

    public function username()
    {
        return filter_var(request('email'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
    }
}

注意: 别忘了把登录表单的 input type="email" 改成 type="text"


Tip 7.登录请求频繁:自定义参数

如果您尝试在同一分钟内使用无效凭据登录五次以上,则请求会被拦截,并显示一条消息尝试登录的次数过多。 请在X秒后重试。

该拦截操作将持续1分钟,并且对于用户的用户名/电子邮件及其IP地址是唯一的。

您可以自定义这些参数:

  • 一分钟内的无效尝试次数(默认为五次尝试)
  • 阻止登录的分钟数(默认为1分钟)

这两个参数在TraitThrottlesLogins内部:

trait ThrottlesLogins
{
    // ... other methods

    /**
     * Get the maximum number of attempts to allow.
     *
     * @return int
     */
    public function maxAttempts()
    {
        return property_exists($this, 'maxAttempts') ? $this->maxAttempts : 5;
    }

    /**
     * Get the number of minutes to throttle for.
     *
     * @return int
     */
    public function decayMinutes()
    {
        return property_exists($this, 'decayMinutes') ? $this->decayMinutes : 1;
    }
}

因此,要覆盖这些属性,可以在 LoginController 内部指定属性:

class LoginController extends Controller
{
    protected $maxAttempts = 3;  // Default is 5
    protected $decayMinutes = 2; // Default is 1

    // ...
}

Tip 8. 注册: 禁用自动登录

默认情况下,新注册的用户将自动登录并重定向到主页。

如果您需要禁用该功能并改为显示注册成功页面,而不自动登录的话,可以执行以下操作。

原始注册方法位于 Trait RegistersUsers 的内部:

trait RegistersUsers
{
    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        $this->guard()->login($user);

        if ($response = $this->registered($request, $user)) {
            return $response;
        }

        return $request->wantsJson()
                    ? new Response('', 201)
                    : redirect($this->redirectPath());
    }

因此,您的目标是在RegisterController中覆盖它,然后重定向到新页面,而不是登录:

class RegisterController extends Controller
{
    use RegistersUsers;

    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        event(new Registered($user = $this->create($request->all())));

        return redirect()->route('your_success_page_route_name');
    }

Tip 9. 登录: 通过电子邮件/密码进行附加检查

如果除了默认的电子邮件和密码外,还需要进行其他检查,该怎么办? 例如,您要检查用户是否处于活动状态或未被禁止。

您可以添加额外的字段 credentials 到定义在 AuthenticatesUsers trait 的鉴权数组中:

trait AuthenticatesUsers
{
    // ...

    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password');
    }

然后只需要重写 LoginController 即可:

class LoginController extends Controller
{
    // ...

    protected function credentials(Request $request)
    {
        return $request->only($this->username(), 'password') + ['is_active' => 1];
    }

注意: 这是一个很有趣的便捷提示,但是我建议您在单独的中间件中执行这种额外的检查,然后向用户提供更明确的错误消息,而不是默认的凭证错误。


就是这些,都是一些便捷提示,但是自定义代码和外部扩展包还有很多可以发挥的地方。 因此,可以继续关注有关该主题的更多文章!

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://laravel-news.com/laravel-auth-ti...

译文地址:https://learnku.com/laravel/t/48905

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 1

厉害了,谢谢分享。

2个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!