認證
- 簡介
- 身份驗證快速入門
- 手動驗證使用者
- HTTP 基礎身份驗證
- 登出
- 密碼確認
- 新增自定義守衛 (Guards)
- 新增自定義使用者提供程式 (User Providers)
- 自動密碼重雜湊
- 社交身份驗證
- 活動
簡介
許多 Web 應用程式都為使用者提供了身份驗證和“登入”的方式。在 Web 應用程式中實現此功能可能是一項複雜且具有潛在風險的工作。因此,Laravel 致力於為您提供快速、安全且輕鬆地實現身份驗證所需的工具。
Laravel 的身份驗證設施的核心由“守衛 (guards)”和“提供程式 (providers)”組成。守衛定義瞭如何對每個請求進行使用者身份驗證。例如,Laravel 自帶一個 session 守衛,它使用會話儲存和 cookie 來維護狀態。
提供程式定義瞭如何從持久儲存中檢索使用者。Laravel 自帶對使用 Eloquent 和資料庫查詢構建器檢索使用者的支援。當然,您可以根據應用程式的需要自由定義其他提供程式。
應用程式的身份驗證配置檔案位於 config/auth.php。該檔案包含多個文件齊全的選項,用於調整 Laravel 身份驗證服務的行為。
守衛和提供程式不應與“角色”和“許可權”混淆。要了解有關透過許可權授權使用者操作的更多資訊,請參閱授權文件。
入門套件
想要快速開始?在全新的 Laravel 應用程式中安裝 Laravel 應用程式入門套件。遷移資料庫後,將瀏覽器導航至 /register 或分配給應用程式的任何其他 URL。入門套件將為您處理整個身份驗證系統的腳手架!
即使您最終決定不在 Laravel 應用程式中使用入門套件,安裝一個入門套件也是學習如何在實際 Laravel 專案中實現 Laravel 所有身份驗證功能的一個絕佳機會。 由於 Laravel 入門套件中包含了身份驗證控制器、路由和檢視,您可以檢視這些檔案中的程式碼,瞭解如何實現 Laravel 的身份驗證功能。
資料庫注意事項
預設情況下,Laravel 在您的 app/Models 目錄中包含一個 App\Models\User Eloquent 模型。此模型可與預設的 Eloquent 身份驗證驅動程式一起使用。
如果您的應用程式不使用 Eloquent,您可以使用使用 Laravel 查詢構建器的 database 身份驗證提供程式。如果您的應用程式使用 MongoDB,請檢視 MongoDB 官方的 Laravel 使用者身份驗證文件。
在為 App\Models\User 模型構建資料庫架構時,請確保密碼列的長度至少為 60 個字元。當然,新 Laravel 應用程式中包含的 users 表遷移已經建立了一個超過此長度的列。
此外,您應該驗證您的 users(或同等)表是否包含一個可為空、長度為 100 個字元的 remember_token 字串列。此列將用於為在登入應用程式時選擇“記住我”選項的使用者儲存令牌。同樣,新 Laravel 應用程式中包含的預設 users 表遷移已經包含了此列。
生態系統概述
Laravel 提供了幾個與身份驗證相關的包。在繼續之前,我們將回顧 Laravel 中的通用身份驗證生態系統,並討論每個包的預期用途。
首先,考慮身份驗證的工作原理。使用 Web 瀏覽器時,使用者將透過登入表單提供其使用者名稱和密碼。如果這些憑據正確,應用程式將在使用者的 會話中儲存有關已驗證使用者的資訊。頒發給瀏覽器的 cookie 包含會話 ID,以便後續對應用程式的請求可以將使用者與正確的會話關聯起來。接收到會話 cookie 後,應用程式將根據會話 ID 檢索會話資料,注意到身份驗證資訊已儲存在會話中,並將該使用者視為“已驗證”。
當遠端服務需要進行身份驗證以訪問 API 時,通常不會使用 cookie 進行身份驗證,因為沒有 Web 瀏覽器。相反,遠端服務會在每次請求時向 API 傳送 API 令牌。應用程式可以將傳入的令牌與有效 API 令牌表進行驗證,並將該請求“驗證”為由與該 API 令牌關聯的使用者執行。
Laravel 內建的瀏覽器身份驗證服務
Laravel 包含內建的身份驗證和會話服務,通常透過 Auth 和 Session 外觀 (facades) 訪問。這些功能為從 Web 瀏覽器發起的請求提供基於 cookie 的身份驗證。它們提供的方法允許您驗證使用者的憑據並對使用者進行身份驗證。此外,這些服務會自動將正確的身份驗證資料儲存在使用者的會話中,並頒發使用者的會話 cookie。本手冊中包含了有關如何使用這些服務的討論。
應用程式入門套件
正如本手冊中所述,您可以手動與這些身份驗證服務互動,以構建您自己的應用程式身份驗證層。但是,為了幫助您更快入門,我們釋出了免費入門套件,提供了整個身份驗證層的穩健、現代的腳手架。
Laravel 的 API 身份驗證服務
Laravel 提供了兩個可選包來協助您管理 API 令牌和驗證使用 API 令牌發出的請求:Passport 和 Sanctum。請注意,這些庫與 Laravel 內建的基於 cookie 的身份驗證庫並非互斥。這些庫主要專注於 API 令牌身份驗證,而內建的身份驗證服務則專注於基於 cookie 的瀏覽器身份驗證。許多應用程式會同時使用 Laravel 內建的基於 cookie 的身份驗證服務和其中一個 Laravel API 身份驗證包。
Passport
Passport 是一個 OAuth2 身份驗證提供程式,提供各種 OAuth2 “授權型別”,允許您頒發各種型別的令牌。總的來說,這是一個用於 API 身份驗證的健壯且複雜的包。但是,大多數應用程式不需要 OAuth2 規範提供的複雜功能,這可能會讓使用者和開發人員感到困惑。此外,開發人員歷來對如何使用像 Passport 這樣的 OAuth2 身份驗證提供程式來驗證 SPA 應用程式或移動應用程式感到困惑。
Sanctum
針對 OAuth2 的複雜性和開發人員的困惑,我們著手構建一個更簡單、更精簡的身份驗證包,既能處理來自 Web 瀏覽器的第一方 Web 請求,也能處理透過令牌進行的 API 請求。這一目標隨著 Laravel Sanctum 的釋出而實現,對於那些除了提供 API 外還將提供第一方 Web UI 的應用程式,或由獨立於後端 Laravel 應用程式存在的單頁應用程式 (SPA) 提供支援的應用程式,或提供移動客戶端的應用程式,應將其視為首選和推薦的身份驗證包。
Laravel Sanctum 是一個混合 Web / API 身份驗證包,可以管理應用程式的整個身份驗證過程。這是可能的,因為當基於 Sanctum 的應用程式接收到請求時,Sanctum 首先會確定請求是否包含引用已驗證會話的會話 cookie。Sanctum 透過呼叫我們之前討論過的 Laravel 內建身份驗證服務來實現這一點。如果請求不是透過會話 cookie 進行驗證的,Sanctum 將檢查請求中的 API 令牌。如果存在 API 令牌,Sanctum 將使用該令牌驗證請求。要了解有關此過程的更多資訊,請查閱 Sanctum 的 “工作原理”文件。
總結與選擇您的堆疊
總之,如果您的應用程式將透過瀏覽器訪問,並且您正在構建單體 Laravel 應用程式,那麼您的應用程式將使用 Laravel 的內建身份驗證服務。
接下來,如果您的應用程式提供將被第三方消費的 API,您將在 Passport 或 Sanctum 之間進行選擇,以為您的應用程式提供 API 令牌身份驗證。通常情況下,應儘可能優先選擇 Sanctum,因為它是一個用於 API 身份驗證、SPA 身份驗證和移動身份驗證的簡單、完整的解決方案,包括對“作用域 (scopes)”或“能力 (abilities)”的支援。
如果您正在構建由 Laravel 後端支援的單頁應用程式 (SPA),則應使用 Laravel Sanctum。使用 Sanctum 時,您需要手動實現自己的後端身份驗證路由,或者利用 Laravel Fortify 作為無頭身份驗證後端服務,它為註冊、密碼重置、電子郵件驗證等功能提供路由和控制器。
當您的應用程式絕對需要 OAuth2 規範提供的所有功能時,可以選擇 Passport。
而且,如果您想快速上手,我們很高興推薦我們的應用程式入門套件,作為啟動一個已經使用我們首選的 Laravel 內建身份驗證服務堆疊的新 Laravel 應用程式的快速方式。
身份驗證快速入門
本文件的這一部分討論了透過 Laravel 應用程式入門套件驗證使用者,其中包括 UI 腳手架,以幫助您快速入門。如果您想直接與 Laravel 的身份驗證系統整合,請檢視有關手動驗證使用者的文件。
安裝入門套件
首先,您應該安裝一個 Laravel 應用程式入門套件。我們的入門套件為將身份驗證合併到您的全新 Laravel 應用程式中提供了設計精美的起點。
獲取已驗證的使用者
使用入門套件建立應用程式並允許使用者在您的應用程式中註冊和驗證後,您通常需要與當前已驗證的使用者進行互動。在處理傳入請求時,您可以透過 Auth 外觀的 user 方法訪問已驗證的使用者
1use Illuminate\Support\Facades\Auth;2 3// Retrieve the currently authenticated user...4$user = Auth::user();5 6// Retrieve the currently authenticated user's ID...7$id = Auth::id();
或者,一旦使用者透過身份驗證,您可以透過 Illuminate\Http\Request 例項訪問已驗證的使用者。請記住,型別提示類將自動注入到您的控制器方法中。透過對 Illuminate\Http\Request 物件進行型別提示,您可以方便地透過請求的 user 方法從應用程式中的任何控制器方法訪問已驗證的使用者
1<?php 2 3namespace App\Http\Controllers; 4 5use Illuminate\Http\RedirectResponse; 6use Illuminate\Http\Request; 7 8class FlightController extends Controller 9{10 /**11 * Update the flight information for an existing flight.12 */13 public function update(Request $request): RedirectResponse14 {15 $user = $request->user();16 17 // ...18 19 return redirect('/flights');20 }21}
確定當前使用者是否已透過身份驗證
要確定發出傳入 HTTP 請求的使用者是否已透過身份驗證,您可以使用 Auth 外觀上的 check 方法。如果使用者已透過身份驗證,此方法將返回 true
1use Illuminate\Support\Facades\Auth;2 3if (Auth::check()) {4 // The user is logged in...5}
儘管可以使用 check 方法確定使用者是否已透過身份驗證,但您通常會在允許使用者訪問某些路由/控制器之前使用中介軟體來驗證使用者是否已透過身份驗證。要了解有關此內容的更多資訊,請檢視有關保護路由的文件。
保護路由
路由中介軟體可用於僅允許已驗證的使用者訪問特定路由。Laravel 自帶 auth 中介軟體,它是 Illuminate\Auth\Middleware\Authenticate 類的中介軟體別名。由於此中介軟體已在 Laravel 內部別名化,您只需將中介軟體附加到路由定義即可
1Route::get('/flights', function () {2 // Only authenticated users may access this route...3})->middleware('auth');
重定向未經身份驗證的使用者
當 auth 中介軟體檢測到未經身份驗證的使用者時,它會將使用者重定向到 login 命名路由。您可以在應用程式的 bootstrap/app.php 檔案中使用 redirectGuestsTo 方法修改此行為
1use Illuminate\Http\Request;2 3->withMiddleware(function (Middleware $middleware): void {4 $middleware->redirectGuestsTo('/login');5 6 // Using a closure...7 $middleware->redirectGuestsTo(fn (Request $request) => route('login'));8})
重定向已驗證的使用者
當 guest 中介軟體檢測到已驗證的使用者時,它會將使用者重定向到 dashboard 或 home 命名路由。您可以在應用程式的 bootstrap/app.php 檔案中使用 redirectUsersTo 方法修改此行為
1use Illuminate\Http\Request;2 3->withMiddleware(function (Middleware $middleware): void {4 $middleware->redirectUsersTo('/panel');5 6 // Using a closure...7 $middleware->redirectUsersTo(fn (Request $request) => route('panel'));8})
指定守衛
將 auth 中介軟體附加到路由時,您還可以指定應使用哪個“守衛”來對使用者進行身份驗證。指定的守衛應對應於 auth.php 配置檔案中 guards 陣列中的鍵之一
1Route::get('/flights', function () {2 // Only authenticated users may access this route...3})->middleware('auth:admin');
登入限流
如果您正在使用我們的應用程式入門套件之一,限流將自動應用於登入嘗試。預設情況下,如果使用者在幾次嘗試後未能提供正確的憑據,他們將在一分鐘內無法登入。限流對於使用者的使用者名稱/電子郵件地址及其 IP 地址是唯一的。
如果您想對應用程式中的其他路由進行限流,請檢視限流文件。
手動驗證使用者
您不需要使用 Laravel 應用程式入門套件中包含的身份驗證腳手架。如果您選擇不使用此腳手架,則需要直接使用 Laravel 身份驗證類來管理使用者身份驗證。別擔心,這很簡單!
我們將透過 Auth 外觀訪問 Laravel 的身份驗證服務,因此我們需要確保在類頂部匯入 Auth 外觀。接下來,讓我們看看 attempt 方法。attempt 方法通常用於處理來自應用程式“登入”表單的身份驗證嘗試。如果身份驗證成功,您應該重新生成使用者的會話,以防止會話固定
1<?php 2 3namespace App\Http\Controllers; 4 5use Illuminate\Http\Request; 6use Illuminate\Http\RedirectResponse; 7use Illuminate\Support\Facades\Auth; 8 9class LoginController extends Controller10{11 /**12 * Handle an authentication attempt.13 */14 public function authenticate(Request $request): RedirectResponse15 {16 $credentials = $request->validate([17 'email' => ['required', 'email'],18 'password' => ['required'],19 ]);20 21 if (Auth::attempt($credentials)) {22 $request->session()->regenerate();23 24 return redirect()->intended('dashboard');25 }26 27 return back()->withErrors([28 'email' => 'The provided credentials do not match our records.',29 ])->onlyInput('email');30 }31}
attempt 方法接受鍵/值對陣列作為其第一個引數。陣列中的值將用於在您的資料庫表中查詢使用者。因此,在上面的示例中,使用者將透過 email 列的值進行檢索。如果找到使用者,資料庫中儲存的雜湊密碼將與透過陣列傳遞給該方法的 password 值進行比較。您不應該對傳入請求的 password 值進行雜湊處理,因為框架會在將其與資料庫中的雜湊密碼進行比較之前自動對其進行雜湊處理。如果兩個雜湊密碼匹配,將為使用者啟動已驗證會話。
請記住,Laravel 的身份驗證服務將根據您的身份驗證守衛的“提供程式”配置從資料庫中檢索使用者。在預設的 config/auth.php 配置檔案中,指定了 Eloquent 使用者提供程式,並指示它在檢索使用者時使用 App\Models\User 模型。您可以根據應用程式的需要在此配置檔案中更改這些值。
如果身份驗證成功,attempt 方法將返回 true。否則,將返回 false。
Laravel 的重定向器提供的 intended 方法會將使用者重定向到他們在被身份驗證中介軟體攔截之前試圖訪問的 URL。如果預期目標不可用,可以為此方法提供一個後備 URI。
指定附加條件
如果需要,除了使用者的電子郵件和密碼外,您還可以向身份驗證查詢新增額外的查詢條件。為此,我們只需將查詢條件新增到傳遞給 attempt 方法的陣列中。例如,我們可以驗證使用者是否被標記為“活躍”
1if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {2 // Authentication was successful...3}
對於複雜的查詢條件,您可以在憑據陣列中提供一個閉包。此閉包將使用查詢例項呼叫,允許您根據應用程式的需求自定義查詢
1use Illuminate\Database\Eloquent\Builder;2 3if (Auth::attempt([4 'email' => $email,5 'password' => $password,6 fn (Builder $query) => $query->has('activeSubscription'),7])) {8 // Authentication was successful...9}
在這些示例中,email 不是必需選項,它僅用作示例。您應該使用資料庫表中對應於“使用者名稱”的任何列名。
接收閉包作為其第二個引數的 attemptWhen 方法可用於在實際驗證使用者之前對潛在使用者進行更廣泛的檢查。閉包接收潛在使用者,並應返回 true 或 false 以指示使用者是否可以進行身份驗證
1if (Auth::attemptWhen([2 'email' => $email,3 'password' => $password,4], function (User $user) {5 return $user->isNotBanned();6})) {7 // Authentication was successful...8}
訪問特定的守衛例項
透過 Auth 外觀的 guard 方法,您可以指定在對使用者進行身份驗證時要利用的守衛例項。這允許您使用完全獨立的身份驗證模型或使用者表來管理應用程式不同部分的身份驗證。
傳遞給 guard 方法的守衛名稱應對應於 auth.php 配置檔案中配置的守衛之一
1if (Auth::guard('admin')->attempt($credentials)) {2 // ...3}
記住使用者
許多 Web 應用程式在登入表單上提供“記住我”複選框。如果您想在應用程式中提供“記住我”功能,可以將布林值作為第二個引數傳遞給 attempt 方法。
當此值為 true 時,Laravel 將無限期地保持使用者處於身份驗證狀態,直到他們手動登出。您的 users 表必須包含字串 remember_token 列,該列將用於儲存“記住我”令牌。新 Laravel 應用程式隨附的 users 表遷移已包含此列
1use Illuminate\Support\Facades\Auth;2 3if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {4 // The user is being remembered...5}
如果您的應用程式提供“記住我”功能,您可以使用 viaRemember 方法來確定當前已驗證的使用者是否使用“記住我”cookie 進行了身份驗證
1use Illuminate\Support\Facades\Auth;2 3if (Auth::viaRemember()) {4 // ...5}
其他身份驗證方法
驗證使用者例項
如果您需要將現有的使用者例項設定為當前已驗證的使用者,您可以將使用者例項傳遞給 Auth 外觀的 login 方法。給定的使用者例項必須是 Illuminate\Contracts\Auth\Authenticatable 契約的實現。Laravel 隨附的 App\Models\User 模型已經實現了此介面。當您已經擁有有效的使用者例項時(例如在使用者註冊應用程式後),此身份驗證方法很有用
1use Illuminate\Support\Facades\Auth;2 3Auth::login($user);
您可以將布林值作為第二個引數傳遞給 login 方法。此值指示已驗證會話是否需要“記住我”功能。請記住,這意味著會話將無限期地進行身份驗證,或者直到使用者手動登出應用程式
1Auth::login($user, $remember = true);
如果需要,您可以在呼叫 login 方法之前指定身份驗證守衛
1Auth::guard('admin')->login($user);
按 ID 驗證使用者
要使用其資料庫記錄的主鍵來驗證使用者,您可以使用 loginUsingId 方法。此方法接受您要驗證的使用者的主鍵
1Auth::loginUsingId(1);
您可以將布林值傳遞給 loginUsingId 方法的 remember 引數。此值指示已驗證會話是否需要“記住我”功能。請記住,這意味著會話將無限期地進行身份驗證,或者直到使用者手動登出應用程式
1Auth::loginUsingId(1, remember: true);
驗證使用者一次
您可以使用 once 方法驗證應用程式的使用者以進行單次請求。呼叫此方法時不會使用任何會話或 cookie,也不會分發 Login 事件
1if (Auth::once($credentials)) {2 // ...3}
HTTP 基礎身份驗證
HTTP 基礎身份驗證提供了一種快速驗證應用程式使用者的方法,而無需設定專門的“登入”頁面。要開始使用,請將 auth.basic 中介軟體附加到路由。auth.basic 中介軟體包含在 Laravel 框架中,因此您無需定義它
1Route::get('/profile', function () {2 // Only authenticated users may access this route...3})->middleware('auth.basic');
一旦中介軟體附加到路由,當您在瀏覽器中訪問該路由時,系統會自動提示您輸入憑據。預設情況下,auth.basic 中介軟體將假定 users 資料庫表上的 email 列是使用者的“使用者名稱”。
關於 FastCGI 的說明
如果您正在使用 PHP FastCGI 和 Apache 來服務您的 Laravel 應用程式,HTTP 基礎身份驗證可能無法正常工作。要糾正這些問題,可以將以下行新增到應用程式的 .htaccess 檔案中
1RewriteCond %{HTTP:Authorization} ^(.+)$2RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
無狀態 HTTP 基礎身份驗證
您也可以在會話中不設定使用者識別符號 cookie 的情況下使用 HTTP 基礎身份驗證。如果您選擇使用 HTTP 身份驗證來驗證對應用程式 API 的請求,這特別有用。為此,定義一箇中間件並呼叫 onceBasic 方法。如果 onceBasic 方法沒有返回響應,則請求可以進一步傳遞到應用程式中
1<?php 2 3namespace App\Http\Middleware; 4 5use Closure; 6use Illuminate\Http\Request; 7use Illuminate\Support\Facades\Auth; 8use Symfony\Component\HttpFoundation\Response; 9 10class AuthenticateOnceWithBasicAuth11{12 /**13 * Handle an incoming request.14 *15 * @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next16 */17 public function handle(Request $request, Closure $next): Response18 {19 return Auth::onceBasic() ?: $next($request);20 }21 22}
接下來,將中介軟體附加到路由
1Route::get('/api/user', function () {2 // Only authenticated users may access this route...3})->middleware(AuthenticateOnceWithBasicAuth::class);
登出
要手動登出應用程式的使用者,您可以使用 Auth 外觀提供的 logout 方法。這將從使用者的會話中刪除身份驗證資訊,以便後續請求不會被驗證。
除了呼叫 logout 方法外,建議您使使用者的會話無效並重新生成他們的 CSRF 令牌。使用者登出後,您通常會將使用者重定向到應用程式的根目錄
1use Illuminate\Http\Request; 2use Illuminate\Http\RedirectResponse; 3use Illuminate\Support\Facades\Auth; 4 5/** 6 * Log the user out of the application. 7 */ 8public function logout(Request $request): RedirectResponse 9{10 Auth::logout();11 12 $request->session()->invalidate();13 14 $request->session()->regenerateToken();15 16 return redirect('/');17}
登出其他裝置上的會話
Laravel 還提供了一種機制,用於使在其他裝置上處於活動狀態的使用者會話失效並“登出”使用者,而無需使當前裝置上的會話無效。當用戶更改或更新其密碼時,並且您希望使其他裝置上的會話失效同時保持當前裝置處於已驗證狀態,通常會使用此功能。
開始之前,您應確保 Illuminate\Session\Middleware\AuthenticateSession 中介軟體已包含在應接收會話身份驗證的路由中。通常,您應該將此中介軟體放在路由組定義中,以便它可以應用於大多數應用程式的路由。預設情況下,AuthenticateSession 中介軟體可以使用 auth.session 中介軟體別名附加到路由
1Route::middleware(['auth', 'auth.session'])->group(function () {2 Route::get('/', function () {3 // ...4 });5});
然後,您可以使用 Auth 外觀提供的 logoutOtherDevices 方法。此方法要求使用者確認其當前密碼,您的應用程式應透過輸入表單接受該密碼
1use Illuminate\Support\Facades\Auth;2 3Auth::logoutOtherDevices($currentPassword);
當呼叫 logoutOtherDevices 方法時,使用者的其他會話將完全失效,這意味著他們將從之前驗證過他們的所有守衛中“登出”。
密碼確認
在構建應用程式時,您偶爾會有一些操作,這些操作要求使用者在執行操作之前或在使用者被重定向到應用程式的敏感區域之前確認其密碼。Laravel 包含內建中介軟體,使此過程變得輕而易舉。實現此功能需要您定義兩個路由:一個路由用於顯示要求使用者確認密碼的檢視,另一個路由用於確認密碼有效並將使用者重定向到其預期目的地。
以下文件討論瞭如何直接與 Laravel 的密碼確認功能整合;但是,如果您想更快上手,Laravel 應用程式入門套件包含了對此功能的支援!
配置
確認密碼後,使用者在三個小時內不會被要求再次確認密碼。但是,您可以透過更改應用程式 config/auth.php 配置檔案中的 password_timeout 配置值來配置使用者被再次提示輸入密碼之前的時間長度。
路由
密碼確認表單
首先,我們將定義一個路由來顯示要求使用者確認其密碼的檢視
1Route::get('/confirm-password', function () {2 return view('auth.confirm-password');3})->middleware('auth')->name('password.confirm');
正如您所料,此路由返回的檢視應包含一個帶有 password 欄位的表單。此外,請隨意在檢視中包含文字,解釋使用者正在進入應用程式的受保護區域,必須確認其密碼。
確認密碼
接下來,我們將定義一個路由來處理來自“確認密碼”檢視的表單請求。此路由將負責驗證密碼並將使用者重定向到其預期目的地
1use Illuminate\Http\Request; 2use Illuminate\Support\Facades\Hash; 3 4Route::post('/confirm-password', function (Request $request) { 5 if (! Hash::check($request->password, $request->user()->password)) { 6 return back()->withErrors([ 7 'password' => ['The provided password does not match our records.'] 8 ]); 9 }10 11 $request->session()->passwordConfirmed();12 13 return redirect()->intended();14})->middleware(['auth', 'throttle:6,1']);
繼續之前,讓我們更詳細地檢查此路由。首先,確定請求的 password 欄位確實與已驗證使用者的密碼匹配。如果密碼有效,我們需要通知 Laravel 的會話使用者已確認其密碼。passwordConfirmed 方法將在使用者的會話中設定一個時間戳,Laravel 可以使用該時間戳來確定使用者上次確認其密碼的時間。最後,我們可以將使用者重定向到其預期目的地。
保護路由
您應確保任何執行需要近期密碼確認的操作的路由都被分配了 password.confirm 中介軟體。此中介軟體包含在 Laravel 的預設安裝中,並將自動將會話中使用者的預期目的地儲存在會話中,以便使用者在確認密碼後可以被重定向到該位置。將使用者的預期目的地儲存在會話中後,中介軟體會將使用者重定向到 password.confirm 命名路由
1Route::get('/settings', function () {2 // ...3})->middleware(['password.confirm']);4 5Route::post('/settings', function () {6 // ...7})->middleware(['password.confirm']);
新增自定義守衛 (Guards)
您可以使用 Auth 外觀上的 extend 方法定義自己的身份驗證守衛。您應該將對 extend 方法的呼叫放在 服務提供程式中。由於 Laravel 已經自帶了 AppServiceProvider,我們可以將程式碼放在該提供程式中
1<?php 2 3namespace App\Providers; 4 5use App\Services\Auth\JwtGuard; 6use Illuminate\Contracts\Foundation\Application; 7use Illuminate\Support\Facades\Auth; 8use Illuminate\Support\ServiceProvider; 9 10class AppServiceProvider extends ServiceProvider11{12 // ...13 14 /**15 * Bootstrap any application services.16 */17 public function boot(): void18 {19 Auth::extend('jwt', function (Application $app, string $name, array $config) {20 // Return an instance of Illuminate\Contracts\Auth\Guard...21 22 return new JwtGuard(Auth::createUserProvider($config['provider']));23 });24 }25}
正如您在上面的示例中看到的,傳遞給 extend 方法的回撥應返回 Illuminate\Contracts\Auth\Guard 的實現。此介面包含幾個您需要實現的方法來定義自定義守衛。定義自定義守衛後,您可以在 auth.php 配置檔案的 guards 配置中引用該守衛
1'guards' => [2 'api' => [3 'driver' => 'jwt',4 'provider' => 'users',5 ],6],
閉包請求守衛
實現自定義、基於 HTTP 請求的身份驗證系統的最簡單方法是使用 Auth::viaRequest 方法。此方法允許您使用單個閉包快速定義您的身份驗證過程。
要開始使用,請在應用程式 AppServiceProvider 的 boot 方法中呼叫 Auth::viaRequest 方法。viaRequest 方法接受身份驗證驅動程式名稱作為其第一個引數。此名稱可以是描述您的自定義守衛的任何字串。傳遞給該方法的第二個引數應是一個閉包,該閉包接收傳入的 HTTP 請求並返回使用者例項,如果身份驗證失敗,則返回 null
1use App\Models\User; 2use Illuminate\Http\Request; 3use Illuminate\Support\Facades\Auth; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 Auth::viaRequest('custom-token', function (Request $request) {11 return User::where('token', (string) $request->token)->first();12 });13}
定義自定義身份驗證驅動程式後,您可以在 auth.php 配置檔案的 guards 配置中將其配置為驅動程式
1'guards' => [2 'api' => [3 'driver' => 'custom-token',4 ],5],
最後,您可以在將身份驗證中介軟體分配給路由時引用該守衛
1Route::middleware('auth:api')->group(function () {2 // ...3});
新增自定義使用者提供程式 (User Providers)
如果您不使用傳統關係資料庫來儲存使用者,則需要使用自己的身份驗證使用者提供程式擴充套件 Laravel。我們將使用 Auth 外觀上的 provider 方法來定義自定義使用者提供程式。使用者提供程式解析器應返回 Illuminate\Contracts\Auth\UserProvider 的實現
1<?php 2 3namespace App\Providers; 4 5use App\Extensions\MongoUserProvider; 6use Illuminate\Contracts\Foundation\Application; 7use Illuminate\Support\Facades\Auth; 8use Illuminate\Support\ServiceProvider; 9 10class AppServiceProvider extends ServiceProvider11{12 // ...13 14 /**15 * Bootstrap any application services.16 */17 public function boot(): void18 {19 Auth::provider('mongo', function (Application $app, array $config) {20 // Return an instance of Illuminate\Contracts\Auth\UserProvider...21 22 return new MongoUserProvider($app->make('mongo.connection'));23 });24 }25}
使用 provider 方法註冊提供程式後,您可以在 auth.php 配置檔案中切換到新的使用者提供程式。首先,定義一個使用您新驅動程式的 provider
1'providers' => [2 'users' => [3 'driver' => 'mongo',4 ],5],
最後,您可以在 guards 配置中引用此提供程式
1'guards' => [2 'web' => [3 'driver' => 'session',4 'provider' => 'users',5 ],6],
使用者提供程式契約
Illuminate\Contracts\Auth\UserProvider 實現負責從持久儲存系統(如 MySQL、MongoDB 等)中獲取 Illuminate\Contracts\Auth\Authenticatable 實現。這兩個介面允許 Laravel 身份驗證機制在無論使用者資料如何儲存或使用何種型別的類來表示已驗證使用者的情況下繼續執行
讓我們看一下 Illuminate\Contracts\Auth\UserProvider 契約
1<?php 2 3namespace Illuminate\Contracts\Auth; 4 5interface UserProvider 6{ 7 public function retrieveById($identifier); 8 public function retrieveByToken($identifier, $token); 9 public function updateRememberToken(Authenticatable $user, $token);10 public function retrieveByCredentials(array $credentials);11 public function validateCredentials(Authenticatable $user, array $credentials);12 public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false);13}
retrieveById 函式通常接收代表使用者的鍵,例如來自 MySQL 資料庫的自動遞增 ID。應檢索並返回匹配 ID 的 Authenticatable 實現。
retrieveByToken 函式透過其唯一的 $identifier 和“記住我” $token 檢索使用者,通常儲存在像 remember_token 這樣的資料庫列中。與前面的方法一樣,此方法應返回具有匹配令牌值的 Authenticatable 實現。
updateRememberToken 方法使用新的 $token 更新 $user 例項的 remember_token。在成功的“記住我”身份驗證嘗試或使用者登出時,會為使用者分配一個新的令牌。
retrieveByCredentials 方法接收嘗試對應用程式進行身份驗證時傳遞給 Auth::attempt 方法的憑據陣列。然後,該方法應“查詢”底層持久儲存以獲取匹配這些憑據的使用者。通常,此方法將執行帶有“where”條件的查詢,該條件搜尋使用者名稱匹配 $credentials['username'] 值的使用者記錄。該方法應返回 Authenticatable 的實現。 此方法不應嘗試進行任何密碼驗證或身份驗證。
validateCredentials 方法應將給定的 $user 與 $credentials 進行比較以驗證使用者。例如,此方法通常會使用 Hash::check 方法將 $user->getAuthPassword() 的值與 $credentials['password'] 的值進行比較。此方法應返回 true 或 false,指示密碼是否有效。
rehashPasswordIfRequired 方法應在需要且受支援的情況下對給定的 $user 的密碼進行重雜湊處理。例如,此方法通常會使用 Hash::needsRehash 方法來確定 $credentials['password'] 值是否需要重雜湊處理。如果密碼需要重雜湊處理,該方法應使用 Hash::make 方法來重雜湊密碼並更新底層持久儲存中的使用者記錄。
Authenticatable 契約
現在我們已經探索了 UserProvider 上的每種方法,讓我們看一下 Authenticatable 契約。請記住,使用者提供程式應從 retrieveById、retrieveByToken 和 retrieveByCredentials 方法中返回此介面的實現
1<?php 2 3namespace Illuminate\Contracts\Auth; 4 5interface Authenticatable 6{ 7 public function getAuthIdentifierName(); 8 public function getAuthIdentifier(); 9 public function getAuthPasswordName();10 public function getAuthPassword();11 public function getRememberToken();12 public function setRememberToken($value);13 public function getRememberTokenName();14}
此介面很簡單。getAuthIdentifierName 方法應返回使用者的“主鍵”列的名稱,getAuthIdentifier 方法應返回使用者的“主鍵”。使用 MySQL 後端時,這很可能是分配給使用者記錄的自動遞增主鍵。getAuthPasswordName 方法應返回使用者的密碼列的名稱。getAuthPassword 方法應返回使用者的雜湊密碼。
此介面允許身份驗證系統與任何“使用者”類一起使用,無論您使用什麼 ORM 或儲存抽象層。預設情況下,Laravel 在 app/Models 目錄中包含一個 App\Models\User 類,該類實現了此介面。
自動密碼重雜湊
Laravel 的預設密碼雜湊演算法是 bcrypt。bcrypt 雜湊的“工作因子”可以透過應用程式的 config/hashing.php 配置檔案或 BCRYPT_ROUNDS 環境變數進行調整。
通常,隨著 CPU / GPU 處理能力的增加,bcrypt 工作因子應隨時間增加。如果您增加了應用程式的 bcrypt 工作因子,Laravel 將在使用者透過 Laravel 入門套件或當您透過 attempt 方法手動驗證使用者時對應用程式進行身份驗證時,優雅且自動地對使用者密碼進行重雜湊處理。
通常,自動密碼重雜湊不應中斷您的應用程式;但是,您可以透過釋出 hashing 配置檔案來停用此行為
1php artisan config:publish hashing
釋出配置檔案後,您可以將 rehash_on_login 配置值設定為 false
1'rehash_on_login' => false,
活動
Laravel 在身份驗證過程中會分發各種事件。您可以為以下任何事件定義監聽器
| 事件名稱 |
|---|
Illuminate\Auth\Events\Registered |
Illuminate\Auth\Events\Attempting |
Illuminate\Auth\Events\Authenticated |
Illuminate\Auth\Events\Login |
Illuminate\Auth\Events\Failed |
Illuminate\Auth\Events\Validated |
Illuminate\Auth\Events\Verified |
Illuminate\Auth\Events\Logout |
Illuminate\Auth\Events\CurrentDeviceLogout |
Illuminate\Auth\Events\OtherDeviceLogout |
Illuminate\Auth\Events\Lockout |
Illuminate\Auth\Events\PasswordReset |
Illuminate\Auth\Events\PasswordResetLinkSent |