
轉(zhuǎn)載自 Laravel 論壇:https://learnku.com/laravel/t/48905
Laravel擁有一個很棒的現(xiàn)成的用戶認證系統(tǒng),當然我們也需要在在某些地方自定義一些配置。對于某些自定義配置,我們并不需要再去尋找一個擴展包或者寫一大堆代碼。讓我們來研究一下這套認證系統(tǒng)背后隱藏著哪些有趣的功能。
技巧 1. Auth::routes() 參數(shù)
我們應該都知道方法 Auth::routes() 來自于 Laravel UI package (在Laravel 7之前, 它被包含在內(nèi)核中)。
但你知道它可以接受一個數(shù)組來啟用/禁用特定的認證路由嗎?
對于Laravel 7,下面是可用的參數(shù)及其默認值:
Auth::routes([
'login' => true,
'logout' => true,
'register' => true,
'reset' => true, // 用于重置密碼
'confirm' => false, // 用于額外的密碼確認
'verify' => false, // 用于郵箱認證
]);
這些參數(shù)僅啟用或禁用某些路由。
要了解它們是如何工作的,可以查看文件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,該怎么辦?如果您創(chuàng)建的是一個僅基于 API 的項目,且在框架中沒有任何前端呢?
您仍然可以使用 Laravel Auth 及其控制器。安裝 Laravel UI 并運行以下命令:
php artisan ui:controllers
它只會生成 app/Http/Controllers/Auth , 因此您不需要 Blade 或 Vue 文件即可使用它們。
請在 Github 存儲庫 中參閱這個 Artisan 命令的實現(xiàn)。
技巧 3. 對敏感操作重新認證密碼
您是否曾經(jīng)維護過 Github 存儲庫,并試圖更改其訪問設置?然后,Github 要求您再次輸入密碼,以確保確實是您在操作。
從 Laravel 6.2 開始,框架中也集成了該功能。
[圖片上傳失敗...(image-90fdb-1600836263361)]
您只需要向要保護的路由添加一個名為password.confirm的中間件即可。
Route::get('/secrets', 'SecretsController@show')->middleware('password.confirm');
Dries Vints 引用自官方功能發(fā)布文章:
如果嘗試訪問該路由,將提示您確認密碼,和在 GitHub 等其他應用程序上看到的一樣。
確認密碼后,默認情況下會在用戶會話中存儲一個時間戳。時間戳持續(xù)3個小時,因此用戶在此期間不必再次輸入密碼。
您可以使用
auth配置文件中的password_timeout配置選項來自定義此持續(xù)時間。
技巧 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屬性指定其他值。
但是,如果您具有更復雜的動態(tài)重定向邏輯,例如需要根據(jù)用戶角色來判斷呢?
您可以在身份驗證控制器中創(chuàng)建一個redirectTo()方法,然后在其中指定條件。該方法將覆蓋$ redirectTo屬性的任何值。
參見示例:
class RegisterController extends Controller
{
protected $redirectTo = RouteServiceProvider::HOME;
protected function redirectTo()
{
if (auth()->user()->role_id == 1) {
return '/admin';
}
return '/home';
}
技巧 5. 快速創(chuàng)建新用戶
如果您需要創(chuàng)建一個新用戶,但還沒有準備好注冊頁面該怎么辦?
只需在您的終端中打開 Laravel Tinker:
php artisan tinker
如果您不熟悉 Tinker,需要知道它是能夠執(zhí)行任何 Laravel / PHP 代碼的命令行工具。因此,在其中,您可以輕松創(chuàng)建用戶,鍵入此 Eloquent 命令并按 Enter:
\App\User::create(['name' => 'Admin', 'email' => 'admin@admin.com', 'password' => bcrypt('somesecurepassword')]);
但是,如果您需要創(chuàng)建許多用戶進行測試,例如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),
];
});
這些是我們創(chuàng)建的“假”用戶的默認值。為此,我們將生成一個 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();
}
要運行它,我們需要執(zhí)行以下命令:
php artisan db:seed --class=UsersSeeder
您可以在Laravel官方文檔中了解更多有關數(shù)據(jù)庫種子的信息。
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 函數(shù),甚至不是 Laravel 函數(shù)。
class LoginController extends Controller
{
// ...
public function username()
{
return filter_var(request('email'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
}
}
注意: 別忘了把登錄表單的
input type="email"改成type="text"
Tip 7.登錄請求頻繁:自定義參數(shù)
如果您嘗試在同一分鐘內(nèi)使用無效憑據(jù)登錄五次以上,則請求會被攔截,并顯示一條消息嘗試登錄的次數(shù)過多。 請在X秒后重試。
該攔截操作將持續(xù)1分鐘,并且對于用戶的用戶名/電子郵件及其IP地址是唯一的。
您可以自定義這些參數(shù):
- 一分鐘內(nèi)的無效嘗試次數(shù)(默認為五次嘗試)
- 阻止登錄的分鐘數(shù)(默認為1分鐘)
這兩個參數(shù)在TraitThrottlesLogins內(nèi)部:
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 內(nèi)部指定屬性:
class LoginController extends Controller
{
protected $maxAttempts = 3; // Default is 5
protected $decayMinutes = 2; // Default is 1
// ...
}
Tip 8. 注冊: 禁用自動登錄
默認情況下,新注冊的用戶將自動登錄并重定向到主頁。
如果您需要禁用該功能并改為顯示注冊成功頁面,而不自動登錄的話,可以執(zhí)行以下操作。
原始注冊方法位于 Trait RegistersUsers 的內(nèi)部:
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. 登錄: 通過電子郵件/密碼進行附加檢查
如果除了默認的電子郵件和密碼外,還需要進行其他檢查,該怎么辦? 例如,您要檢查用戶是否處于活動狀態(tài)或未被禁止。
您可以添加額外的字段 credentials 到定義在 AuthenticatesUsers trait 的鑒權數(shù)組中:
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];
}
注意: 這是一個很有趣的便捷提示,但是我建議您在單獨的中間件中執(zhí)行這種額外的檢查,然后向用戶提供更明確的錯誤消息,而不是默認的憑證錯誤。
就是這些,都是一些便捷提示,但是自定義代碼和外部擴展包還有很多可以發(fā)揮的地方。 因此,可以繼續(xù)關注有關該主題的更多文章!
討論請前往專業(yè)的 Laravel 論壇:https://learnku.com/laravel/t/48905