Laravel 认证的 9 个快速技巧
发布时间:作者: PovilasKorop
Laravel 拥有出色的开箱即用的 Auth 系统,但我们肯定需要在这里和那里定制一些东西。对于其中一些,不需要寻找外部包或编写很多自定义代码,让我们探索 Auth 底层隐藏的有趣功能。
技巧 1. Auth::routes() 参数
我们可能都知道来自 Laravel UI 包(在 Laravel 7 之前,它包含在核心代码中)的 Auth::routes()
方法。
但你知道它可以接受一个参数数组来启用/禁用某些 Auth 路由吗?
从 Laravel 7 开始,以下是可能的参数及其默认值
Auth::routes([ 'login' => true, 'logout' => true, 'register' => true, 'reset' => true, // for resetting passwords 'confirm' => false, // for additional password confirmations 'verify' => false, // for email verification]);
这些参数只是启用或禁用一些路由。
要了解它们的工作原理,可以查看文件 Laravel UI 中的 AuthRouteMethods
return function ($options = []) { // Login Routes... if ($options['login'] ?? true) { $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); $this->post('login', 'Auth\LoginController@login'); } // Logout Routes... if ($options['logout'] ?? true) { $this->post('logout', 'Auth\LoginController@logout')->name('logout'); } // Registration Routes... if ($options['register'] ?? true) { $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); $this->post('register', 'Auth\RegisterController@register'); } // Password Reset Routes... if ($options['reset'] ?? true) { $this->resetPassword(); } // Password Confirmation Routes... if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) { $this->confirmPassword(); } // Email Verification Routes... if ($options['verify'] ?? false) { $this->emailVerification(); }};
技巧 2. Laravel UI:仅生成控制器
官方文档指定了使用 Laravel UI 的主要方式
php artisan ui vue --auth
但是,如果你不需要可视化 UI 呢?如果你只创建一个基于 API 的项目,并且在 Laravel 端没有任何前端呢?
你仍然可以使用 Laravel Auth 及其控制器。安装 Laravel UI 包并运行以下命令
php artisan ui:controllers
它只会生成 app/Http/Controllers/Auth
内容,因此你不需要 Blade/Vue 文件来使用它们。
查看此 Artisan 命令的实现 在 Github 存储库中。
技巧 3. 重新确认重要设置的密码
你是否曾经维护过一个 Github 存储库,并试图更改其访问设置?然后 Github 会要求你再次输入你的密码,只是为了确保是你。
从 Laravel 6.2 开始,我们在框架中也拥有此功能。
你只需要将名为 password.confirm
的中间件添加到要保护的路由中。
Route::get('/secrets', 'SecretsController@show')->middleware('password.confirm');
引用来自官方 功能发布文章的 Dries Vints
如果你尝试访问该路由,系统会提示你确认密码,类似于你可能在 Github 等其他应用程序中看到的情况。
确认密码将在用户的会话中存储一个时间戳,该时间戳默认持续三个小时,因此用户在此期间无需再次输入密码。
你可以使用
auth
配置文件中的新password_timeout
配置选项自定义此持续时间。_
技巧 4. 注销其他设备
从 Laravel 5.6 开始,我们拥有一个单独的方法,可以自动注销使用我们的帐户登录的任何其他设备或浏览器
Auth::logoutOtherDevices($password);
典型的用法是在当前设备成功登录时注销其他设备。为此,我们覆盖了来自 AuthenticatesUsers.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
属性的值,更改为其他常量,也许分别为登录和注册。
但是,如果你有更复杂的动态重定向逻辑,例如取决于用户角色呢?
你可以在这些 Auth 控制器中创建一个方法,将其称为 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 命令并按回车键
\App\User::create(['name' => 'Admin', 'email' => '[email protected]', 'password' => bcrypt('somesecurepassword')]);
但是,如果你需要创建许多用户进行测试,例如 10 个、100 个或 1000 个呢?没问题,我们可以使用默认情况下与 Laravel 一起提供的工厂类,位于 database/factories/UserFactory.php
中
$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', // password '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 官方文档中阅读有关数据库播种的更多信息。
技巧 6. 使用电子邮件和/或用户名登录
默认情况下,Laravel 用户使用电子邮件和密码进行身份验证。但是,如果你的标识符不是电子邮件呢?例如,某种用户名。
你可以通过覆盖 AuthenticatesUsers.php
特性的一个方法轻松更改它。
以下是默认值
trait AuthenticatesUsers{ // ... other methods public function username() { return 'email'; }
你可以将它复制到 LoginController.php
中,只更改值
class LoginController extends Controller{ use AuthenticatesUsers; // ... other methods 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"
技巧 7. 登录尝试次数过多:自定义参数
如果你在同一分钟内尝试使用无效的凭据登录超过五次,你将被阻止,并显示消息登录尝试次数过多。请在 X 秒后重试。
该阻止将持续 1 分钟,并且对于用户的用户名/电子邮件和他们的 IP 地址是唯一的。
你可以自定义这些参数
- 一分钟内的无效尝试次数(默认五次尝试)
- 阻止登录的分钟数(默认 1 分钟)
这两个参数都在 ThrottlesLogins
特性中
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 // ...}
技巧 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'); }
技巧 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]; }
注意:这是一个有趣的快速技巧,但我建议您在单独的中间件中执行此类额外检查,这样您就可以向用户提供更明确的错误消息,而不是默认的凭据错误。
就是这样,这些是快速技巧,但还有更多内容可以通过自定义代码和外部包进行扩展。敬请关注更多关于该主题的文章!