轉載自 Laravel 論壇: https://learnku.com/laravel/t...
Laravel擁有一個很棒的現成的用戶認證系統,固然咱們也須要在在某些地方自定義一些配置。對於某些自定義配置,咱們並不須要再去尋找一個擴展包或者寫一大堆代碼。讓咱們來研究一下這套認證系統背後隱藏着哪些有趣的功能。php
咱們應該都知道方法 Auth::routes()
來自於 Laravel UI package (在Laravel 7以前, 它被包含在內核中)。前端
但你知道它能夠接受一個數組來啓用/禁用特定的認證路由嗎?vue
對於Laravel 7,下面是可用的參數及其默認值:laravel
Auth::routes([ 'login' => true, 'logout' => true, 'register' => true, 'reset' => true, // 用於重置密碼 'confirm' => false, // 用於額外的密碼確認 'verify' => false, // 用於郵箱認證 ]);
這些參數僅啓用或禁用某些路由。git
要了解它們是如何工做的,能夠查看文件Laravel UI中的AuthRouteMethods:github
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(); } };
官方文檔指定了使用 Laravel UI 的主要方法:web
php artisan ui vue --auth
可是,若是您不須要可視 UI,該怎麼辦?若是您建立的是一個僅基於 API 的項目,且在框架中沒有任何前端呢?數據庫
您仍然可使用 Laravel Auth 及其控制器。安裝 Laravel UI 並運行如下命令:數組
php artisan ui:controllers
它只會生成 app/Http/Controllers/Auth
, 所以您不須要 Blade 或 Vue 文件便可使用它們。瀏覽器
請在 Github 存儲庫 中參閱這個 Artisan 命令的實現。
您是否曾經維護過 Github 存儲庫,並試圖更改其訪問設置?而後,Github 要求您再次輸入密碼,以確保確實是您在操做。
從 Laravel 6.2 開始,框架中也集成了該功能。
您只須要向要保護的路由添加一個名爲password.confirm
的中間件便可。
Route::get('/secrets', 'SecretsController@show')->middleware('password.confirm');
Dries Vints 引用自官方功能發佈文章:
若是嘗試訪問該路由,將提示您確認密碼,和在 GitHub 等其餘應用程序上看到的同樣。確認密碼後,默認狀況下會在用戶會話中存儲一個時間戳。時間戳持續3個小時,所以用戶在此期間沒必要再次輸入密碼。
您可使用
auth
配置文件中的password_timeout
配置選項來自定義此持續時間。
從 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'; }
若是您須要建立一個新用戶,但尚未準備好註冊頁面該怎麼辦?
只需在您的終端中打開 Laravel Tinker:
php artisan tinker
若是您不熟悉 Tinker,須要知道它是可以執行任何 Laravel / PHP 代碼的命令行工具。所以,在其中,您能夠輕鬆建立用戶,鍵入此 Eloquent 命令並按 Enter:
\App\User::create(['name' => 'Admin', 'email' => 'admin@admin.com', 'password' => bcrypt('somesecurepassword')]);
可是,若是您須要建立許多用戶進行測試,例如十、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官方文檔中瞭解更多有關數據庫種子的信息。
默認狀況下,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"
若是您嘗試在同一分鐘內使用無效憑據登陸五次以上,則請求會被攔截,並顯示一條消息嘗試登陸的次數過多。 請在X秒後重試。
該攔截操做將持續1分鐘,而且對於用戶的用戶名/電子郵件及其IP地址是惟一的。
您能夠自定義這些參數:
這兩個參數在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 // ... }
默認狀況下,新註冊的用戶將自動登陸並重定向到主頁。
若是您須要禁用該功能並改成顯示註冊成功頁面,而不自動登陸的話,能夠執行如下操做。
原始註冊方法位於 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'); }
若是除了默認的電子郵件和密碼外,還須要進行其餘檢查,該怎麼辦? 例如,您要檢查用戶是否處於活動狀態或未被禁止。
您能夠添加額外的字段 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]; }
注意: 這是一個頗有趣的便捷提示,可是我建議您在單獨的中間件中執行這種額外的檢查,而後向用戶提供更明確的錯誤消息,而不是默認的憑證錯誤。
就是這些,都是一些便捷提示,可是自定義代碼和外部擴展包還有不少能夠發揮的地方。 所以,能夠繼續關注有關該主題的更多文章!
討論請前往專業的 Laravel 論壇: https://learnku.com/laravel/t...