
使用者認證是Web應用程式最關鍵和最重要的功能之一。像Laravel這樣的Web框架為使用者提供了許多認證方式。
你可以快速而安全地實現Laravel的使用者認證功能。然而, 實現這些使用者安全認證功能不力會有風險, 因為惡意的人可以利用它們.
本指南將教你所有你需要知道的,以開始使用你選擇的Laravel使用者認證方法。
- Laravel使用者認證介紹
- Laravel使用者認證方法的型別
- 如何實現Laravel使用者認證
- Laravel Breeze
- Laravel Jetstream
- Laravel Fortify
- Laravel Socialite
- Laravel Sanctum
- Laravel使用者認證的技巧和最佳實踐
Laravel使用者認證介紹
Laravel引入了由 “守護者(guards)” 和 “提供者(providers)” 組成的模組。守護者為每個請求定義使用者認證, 而提供者定義使用者從永續性儲存(如MySQL資料庫)檢索.
我們在一個名為 config/auth.php
的檔案中定義我們的認證引數。它包括幾個選項來調整和修改Laravel的使用者認證行為。
首先, 你必須定義使用者認證的預設值. 這個選項控制你的應用程式的預設使用者認證 “防護” 和密碼重置選項。你可以根據需要改變這些預設值, 但對於大多數應用程式來說, 它們是一個完美的開始.
接下來,你要為你的應用程式定義使用者認證防護。這裡,我們的預設配置使用會話儲存和Eloquent使用者提供者。所有的認證驅動都有一個使用者提供者。
Defining Authentication Defaults
Defining Authentication Guards
Supported: "database", "eloquent"
'model' => App\Models\User::class,
// 'driver' => 'database',
Defining Password Resetting
'table' => 'password_resets',
Defining Password Confirmation Timeout
'password_timeout' => 10800,
return [
/*
Defining Authentication Defaults
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
Defining Authentication Guards
Supported: "session"
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
Defining User Providers
Supported: "database", "eloquent"
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
Defining Password Resetting
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
Defining Password Confirmation Timeout
*/
'password_timeout' => 10800,
];
return [
/*
Defining Authentication Defaults
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
Defining Authentication Guards
Supported: "session"
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
Defining User Providers
Supported: "database", "eloquent"
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
Defining Password Resetting
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
Defining Password Confirmation Timeout
*/
'password_timeout' => 10800,
];
後來,我們確保所有的使用者認證驅動都有一個使用者提供者。這定義瞭如何從你的資料庫或其他儲存機制中檢索使用者,以持久儲存你的使用者資料。如果你有多個使用者表或模型,你可以配置多個代表每個模型或表的來源。這些源可以被分配給你定義的任何額外的使用者認證衛士。
使用者也可能想重置他們的密碼。為此,如果你在應用程式中有多個使用者表或模型,並希望根據特定的使用者型別進行單獨設定,你可以指定多個密碼重置配置。過期時間是每個重置令牌的有效分鐘數。這個安全功能使令牌的有效期很短,所以它們有更少的時間被猜中。你可以根據需要改變這一點。
最終,你必須定義密碼確認超時前的時間,並提示使用者通過確認螢幕重新輸入密碼。預設情況下,超時時間為三小時。
Laravel使用者認證方法的型別
沒有完美的方式來驗證每一個場景, 但瞭解它們會幫助你做出更好的決定. 這和Laravel在Laravel 9中的新功能的發展情況。這使得我們在切換使用者認證模式時,作為開發者的工作變得更加容易。
基於密碼的使用者認證
作為驗證使用者的基本方式,它仍然被成千上萬的組織所使用,但考慮到目前的發展,它顯然已經過時了。
供應商必須執行復雜的密碼實現,同時確保對終端使用者的摩擦最小。
它的工作原理非常簡單,使用者輸入姓名和密碼,如果在資料庫中,這兩者之間存在匹配,伺服器就會決定對請求進行認證,並讓使用者在預定的時間內訪問資源。
基於令牌的使用者認證
這種方法的使用是在驗證後向使用者發放一個獨特的令牌。
有了這個令牌,現在使用者可以訪問相關的資源。在令牌過期之前,該特權是有效的。
當令牌處於啟用狀態時,使用者不必使用任何使用者名稱或密碼,但在檢索新的令牌時,需要使用這兩個。
今天,令牌被廣泛地用於多種場景,因為它們是包含所有認證資料的無狀態實體。
提供一種將令牌生成與令牌驗證分開的方法給了供應商很大的靈活性。
多因子使用者認證
顧名思義,它意味著使用至少兩個認證因素,提高了它的安全性。
與只涉及兩個因子的二步認證不同,這種方法可以涉及兩個、三個、四個和更多的因素…。
這種方法的典型實施包括使用一個密碼,之後使用者會在他們的智慧手機上收到一個驗證碼。實施這種方法的供應商應該注意假陽性和網路中斷的問題,這在快速擴大規模時可能成為大問題。
如何實現Laravel使用者認證
本節將教你多種方法來驗證你的應用程式的使用者。一些庫,如Jetstream、Breeze和Socialite,都有免費的教程介紹如何使用它們。
傳統使用者認證
從註冊使用者開始,在 routes/web.php
中建立需要的路由。
我們將建立兩條路線,一條用於檢視錶格,一條用於註冊:
use App\Http\Contrllers\Auth\RegisterController;
use Illuminate\Support\Facades\Route;
Register web routes for your app's RouteServiceProvider
in a group containing the "web" middleware
Route::get('/register', [RegisterController::class], 'create']);
Route::post('/register', [RegisterController::class], 'store']);
use App\Http\Contrllers\Auth\RegisterController;
use Illuminate\Support\Facades\Route;
/*
Web Routes
Register web routes for your app's RouteServiceProvider
in a group containing the "web" middleware
*/
Route::get('/register', [RegisterController::class], 'create']);
Route::post('/register', [RegisterController::class], 'store']);
use App\Http\Contrllers\Auth\RegisterController;
use Illuminate\Support\Facades\Route;
/*
Web Routes
Register web routes for your app's RouteServiceProvider
in a group containing the "web" middleware
*/
Route::get('/register', [RegisterController::class], 'create']);
Route::post('/register', [RegisterController::class], 'store']);
並建立這些所需的控制器:
php artisan make controller Auth/RegisterController -r
php artisan make controller Auth/RegisterController -r
php artisan make controller Auth/RegisterController -r
現在更新程式碼,如下:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use illuminate\Htpp\Request;
class RegisterController extends Controller
return view('auth.register');
public function store(Request $request)
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use illuminate\Htpp\Request;
class RegisterController extends Controller
{
public function create()
{
return view('auth.register');
}
public function store(Request $request)
{
}
}
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use illuminate\Htpp\Request;
class RegisterController extends Controller
{
public function create()
{
return view('auth.register');
}
public function store(Request $request)
{
}
}
控制器現在是空的,並返回一個檢視來註冊。讓我們在 resources/views/auth
中製作這個檢視,並將其稱為 register.blade.php
。

用於註冊使用者的Laravel blade檢視
現在一切就緒,我們應該訪問我們的 /register
路線,並看到以下表格:
public function store(Request $request)
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->filled('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/');
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
public function store(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->filled('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/');
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
}
public function store(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->filled('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/');
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
}
現在我們可以顯示一個使用者可以完成的表單,並獲得其中的資料,我們應該獲得使用者的資料,對其進行驗證,如果一切正常,再將其儲存在資料庫中。在這裡,你應該使用一個資料庫事務來確保你插入的資料是完整的。
我們將使用Laravel的請求驗證功能來確保這三個憑證都是必需的。我們必須確保電子郵件有一個電子郵件格式,並且在 users
表中是唯一的,密碼是確認的,並且至少有8個字元:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class RegisterController extends Controller
public function store(Request $request)
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
return view('auth.register');
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class RegisterController extends Controller
{
public function store(Request $request)
{
/*
Validation
*/
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
]);
/*
Database Insert
*/
$user = User:;create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
return back();
}
public function create()
{
return view('auth.register');
}
}
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class RegisterController extends Controller
{
public function store(Request $request)
{
/*
Validation
*/
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
]);
/*
Database Insert
*/
$user = User:;create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
return back();
}
public function create()
{
return view('auth.register');
}
}
現在,我們的輸入已被驗證,任何違反驗證的東西都會丟擲一個錯誤,並顯示在表單中:

無效的註冊輸入的例子
假設我們已經在 store
方法中建立了一個使用者賬戶,我們還想登入該使用者。我們有兩種方法可以做到這一點。我們可以手動操作或使用Auth facade。
在使用者登入後,我們不應該讓他們返回到註冊介面,而應該返回到一個新的頁面,比如儀表盤或主頁。這就是我們在這裡要做的:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class RegisterController extends Controller
public function store(Request $request)
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
return redirect(RouteServiceProvider::HOME);
return view('auth.register');
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class RegisterController extends Controller
{
public function store(Request $request)
{
/*
Validation
*/
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
]);
/*
Database Insert
*/
$user = User:;create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
Auth::login($user):
return redirect(RouteServiceProvider::HOME);
}
public function create()
{
return view('auth.register');
}
}
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class RegisterController extends Controller
{
public function store(Request $request)
{
/*
Validation
*/
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
]);
/*
Database Insert
*/
$user = User:;create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
Auth::login($user):
return redirect(RouteServiceProvider::HOME);
}
public function create()
{
return view('auth.register');
}
}
現在我們已經有一個使用者註冊並登入了 -n
, 我們應該確保他可以安全地登出.
Laravel建議我們在登出後使會話失效並重新生成令牌以保證安全. 而這正是我們要做的. 我們首先使用LogoutController的 destroy
方法建立一個新的 /logout
路由:
use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\LogoutController;
use Illuminate\Support\Facades\Route;
Here is where you can register web routes for your application. These
routes are loaded by the RrouteServiceProvider with a group which
contains the "web" middleware group. Now create something great!
Route::get('/register', [RegisterController::class, 'create']);
Route::post('/register', ['RegisterController::class, 'store']);
Route::post('/logout', [Logoutcontroller::class, 'destroy'])
use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\LogoutController;
use Illuminate\Support\Facades\Route;
/*
Web Routes
Here is where you can register web routes for your application. These
routes are loaded by the RrouteServiceProvider with a group which
contains the "web" middleware group. Now create something great!
*/
Route::get('/register', [RegisterController::class, 'create']);
Route::post('/register', ['RegisterController::class, 'store']);
Route::post('/logout', [Logoutcontroller::class, 'destroy'])
->middleware('auth');
use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\LogoutController;
use Illuminate\Support\Facades\Route;
/*
Web Routes
Here is where you can register web routes for your application. These
routes are loaded by the RrouteServiceProvider with a group which
contains the "web" middleware group. Now create something great!
*/
Route::get('/register', [RegisterController::class, 'create']);
Route::post('/register', ['RegisterController::class, 'store']);
Route::post('/logout', [Logoutcontroller::class, 'destroy'])
->middleware('auth');
通過 “auth” 中介軟體傳遞登出資訊是非常重要的。如果使用者沒有登入,他們應該無法訪問該路線。
現在,像我們之前那樣建立一個控制器:
php artisan make:controller Auth/LogoutController -r
php artisan make:controller Auth/LogoutController -r
php artisan make:controller Auth/LogoutController -r
我們可以確保在 destroy
方法中獲得作為引數的請求。我們通過Auth facade登出使用者,使會話無效,然後重新生成令牌,然後將使用者重定向到主頁:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LogoutController extends Controller
public function destroy(Request $request)
$request->session()->invalidate();
$request->session()->regenerateToken();
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LogoutController extends Controller
{
public function destroy(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LogoutController extends Controller
{
public function destroy(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
}
保持登入
大多數(如果不是全部的話)現代網路應用程式在其登入表單上提供了一個 “remember me” 的覈取方塊。
如果我們想提供一個 “remember me” 的功能, 我們可以傳遞一個布林值作為嘗試方法的第二個引數。
當有效時, Laravel會無限期地保持使用者的身份驗證,或直到他們被手動登出。使用者表必須包括字串 remember_token
(這就是我們重新生成令牌的原因)列, 我們將在這裡儲存我們的 “remember me” 令牌.
使用者的預設遷移已經包括了它。
首先,你必須在你的表單中新增Remember Me欄位:

新增remember me欄位表單
在這之後,從請求中獲得證書並在Auth facade的嘗試方法中使用它們。
如果使用者應該被記住,我們將登入他並把他重定向到我們的主頁。否則,我們將丟擲一個錯誤:
public function store(Request $request)
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->filled('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/');
return back()->withErrors([
public function store(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->filled('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/');
}
return back()->withErrors([
'email' =>
public function store(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials, $request->filled('remember'))) {
$request->session()->regenerate();
return redirect()->intended('/');
}
return back()->withErrors([
'email' =>
重置密碼
今天,大多數網路應用提供了讓使用者重置密碼的途徑。
我們將為忘記密碼的使用者制定另一個路由,並像我們一樣建立控制器。此外,我們將為重置密碼的連結新增一個路由,其中包含整個過程的令牌:
Route::post('/forgot-password', [ForgotPasswordLinkController::class, 'store']);
Route::post('/forgot-password/{token}', [ForgotPasswordController::class, 'reset']);
Route::post('/forgot-password', [ForgotPasswordLinkController::class, 'store']);
Route::post('/forgot-password/{token}', [ForgotPasswordController::class, 'reset']);
Route::post('/forgot-password', [ForgotPasswordLinkController::class, 'store']);
Route::post('/forgot-password/{token}', [ForgotPasswordController::class, 'reset']);
在儲存方法中,我們將從請求中獲取電子郵件,並像我們一樣對其進行驗證。
在這之後,我們可以使用密碼介面的 sendResetLink
方法。
然後,作為一個響應,如果它成功地傳送了連結,我們要返回狀態,否則就是錯誤:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
class ForgotPasswordLinkController extends Controller
public function store(Request $request)
'email' => 'required|email',
$status = Password::sendResetLink(
return $status === Password::RESET_LINK_SENT
? back()->with('status', __($status))
: back()->withInput($request->only('email'))->withErrors(['email' => __($status)]);
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
class ForgotPasswordLinkController extends Controller
{
public function store(Request $request)
{
$request->validate([
'email' => 'required|email',
]);
$status = Password::sendResetLink(
$request->only('email');
);
return $status === Password::RESET_LINK_SENT
? back()->with('status', __($status))
: back()->withInput($request->only('email'))->withErrors(['email' => __($status)]);
}
}
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;
class ForgotPasswordLinkController extends Controller
{
public function store(Request $request)
{
$request->validate([
'email' => 'required|email',
]);
$status = Password::sendResetLink(
$request->only('email');
);
return $status === Password::RESET_LINK_SENT
? back()->with('status', __($status))
: back()->withInput($request->only('email'))->withErrors(['email' => __($status)]);
}
}
現在,重置連結已經傳送到使用者的郵箱,我們應該處理之後發生的邏輯問題。
我們將在請求中獲得令牌,電子郵件和新密碼,並驗證它們。
在這之後, 我們可以使用密碼介面的重置方法, 讓Laravel來處理幕後的其他事情.
我們總是要對密碼進行雜湊處理以保證它的安全。
最後, 我們將檢查密碼是否被重置, 如果是的話, 我們將把使用者重定向到登入介面, 並顯示成功資訊. 否則,我們會顯示一個錯誤,說它無法被重置:
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
class ForgotPasswordController extends Controller
public function store(Request $request)
'email' => 'required|email',
'password' => 'required|string|confirmed|min:8',
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
'password' => Hash::make($request->password),
'remember_token' => Str::random(60)
return $status == Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withInput($request->only('email'))->withErrors(['email' => __($status)]);
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
class ForgotPasswordController extends Controller
{
public function store(Request $request)
{
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|string|confirmed|min:8',
]);
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
$user->forceFill(
'password' => Hash::make($request->password),
'remember_token' => Str::random(60)
])->save();
}
);
return $status == Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withInput($request->only('email'))->withErrors(['email' => __($status)]);
}
}
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
class ForgotPasswordController extends Controller
{
public function store(Request $request)
{
$request->validate([
'token' => 'required',
'email' => 'required|email',
'password' => 'required|string|confirmed|min:8',
]);
$status = Password::reset(
$request->only('email', 'password', 'password_confirmation', 'token'),
function ($user) use ($request) {
$user->forceFill(
'password' => Hash::make($request->password),
'remember_token' => Str::random(60)
])->save();
}
);
return $status == Password::PASSWORD_RESET
? redirect()->route('login')->with('status', __($status))
: back()->withInput($request->only('email'))->withErrors(['email' => __($status)]);
}
}
Laravel Breeze
Laravel Breeze是Laravel使用者認證功能的一個簡單實現方案:登入,註冊,密碼重置,電子郵件驗證和密碼確認。你可以用它來實現你的新Laravel應用程式的認證。
安裝和配置
在建立你的Laravel應用程式後,你所要做的就是配置你的資料庫,執行你的遷移,並通過composer安裝laravel/breeze軟體包:
composer require laravel/breeze –dev
composer require laravel/breeze –dev
composer require laravel/breeze –dev
在這之後,執行以下內容:
php artisan breeze:install
php artisan breeze:install
php artisan breeze:install
這將釋出你的認證檢視、路由、控制器和其他它使用的資源。在這一步之後,你可以完全控制Breeze所提供的一切。
現在我們必須把我們的應用程式渲染到前端,所以我們將安裝我們的JS依賴(將使用@vite):
npm install
npm run dev
在這之後,登入和註冊連結應該出現在你的主頁上,一切都應該順利進行。
Laravel Jetstream
Laravel Jetstream擴充套件了Laravel Breeze的有用功能和其他前端堆疊。
它提供了登入,註冊,電子郵件驗證,雙因子認證,會話管理,通過Sanctum支援API,以及可選的團隊管理。
在安裝Jetstream時,你必須在前端的Livewire和Inertia之間進行選擇。在後端,它使用Laravel Fortify,這是一個與前端無關的,用於Laravel的 “無頭” 使用者認證後端。
安裝和配置
我們將通過composer在我們的Laravel專案中安裝它:
composer require laravel/jetstream
composer require laravel/jetstream
composer require laravel/jetstream
之後,我們將執行 php artisan jetstream:install [stack]
命令,該命令接受 [stack]
引數 Livewire
或 Inertia
。你可以通過 –team
選項來啟用團隊功能。
這也將安裝Pest PHP用於測試。
最後,我們要用下面的方法渲染我們應用程式的前端:
npm install
npm run dev
Laravel Fortify
Laravel Fortify是一個後端認證實現,與前端無關。你不需要使用Laravel Fortify來實現Laravel的認證功能.
它也被用在Breeze和Jetstream這樣的入門套件中。你也可以單獨使用Fortify, 這只是一個後端實現。如果你獨立使用它, 你的前端必須呼叫Fortify路由。
安裝和配置
我們可以通過composer來安裝Fortify:
composer require laravel/fortify
composer require laravel/fortify
composer require laravel/fortify
現在我們要釋出Fortify的資源:
php artisan vendor:publish –provider="Laravel\Fortify\FortifyServiceProvider"
php artisan vendor:publish –provider="Laravel\Fortify\FortifyServiceProvider"
php artisan vendor:publish –provider="Laravel\Fortify\FortifyServiceProvider"
之後,除了新的FortifyServiceProvider、配置檔案和資料庫遷移之外,我們將建立一個新的app/Actions目錄。
最後,執行:
php artisan migrate
或者:
php artisan migrate:fresh
php artisan migrate:fresh
php artisan migrate:fresh
而你的Fortify已經可以使用了。
Laravel Socialite
Laravel包括一個直接的基於OAuth的使用者認證功能。它支援通過Facebook,Twitter,LinkedIn,Google,Bitbucket,GitHub和GitLab進行社交登入。
安裝
我們可以通過composer來安裝它:
composer require laravel/socialite
composer require laravel/socialite
composer require laravel/socialite
配置和使用
安裝完畢後,我們必須為我們的應用程式使用的OAuth提供者新增憑證。我們將在config/services.php中新增每個服務的憑證。
在配置中,我們應該與之前的服務匹配金鑰。其中的一些金鑰包括:
- facebook
- twitter (For OAuth 1.0)
- twitter-oauth-2 (For OAuth 2.0)
- linkedin
- google
- github
- gitlab
- bitbucket
OAuth使用者認證服務配置可能看起來像這樣:
'client_id' => env("GOOGLE_CLIENT_ID"),
'client_secret' => env("GOOGLE_CLIENT_SECRET"),
'redirect' => "http://example.com/callback-url",
'google' => [
'client_id' => env("GOOGLE_CLIENT_ID"),
'client_secret' => env("GOOGLE_CLIENT_SECRET"),
'redirect' => "http://example.com/callback-url",
],
'google' => [
'client_id' => env("GOOGLE_CLIENT_ID"),
'client_secret' => env("GOOGLE_CLIENT_SECRET"),
'redirect' => "http://example.com/callback-url",
],
驗證使用者身份
對於這個動作,我們將需要兩條路由,一條用於將使用者重定向到OAuth提供者:
use Laravel\Socialite\Facades\Sociliate;
Route::get('/auth/redirect', function () {
return Socialite:;driver('google')->redirect();
use Laravel\Socialite\Facades\Sociliate;
Route::get('/auth/redirect', function () {
return Socialite:;driver('google')->redirect();
});
use Laravel\Socialite\Facades\Sociliate;
Route::get('/auth/redirect', function () {
return Socialite:;driver('google')->redirect();
});
還有一個用於認證後的提供者的回撥:
use Laravel\Socialite\Facades\Socialite;
Route:;get('/auht/callback', function () {
$user = Socialite:;driver('google')->user();
use Laravel\Socialite\Facades\Socialite;
Route:;get('/auht/callback', function () {
$user = Socialite:;driver('google')->user();
// Getting the user data
$user->token;
});
use Laravel\Socialite\Facades\Socialite;
Route:;get('/auht/callback', function () {
$user = Socialite:;driver('google')->user();
// Getting the user data
$user->token;
});
Socialite提供了重定向方法,門面將使用者重定向到OAuth提供者,而使用者方法則檢查傳入的請求並檢索使用者資訊。
在我們收到使用者後,我們要檢查它是否存在於我們的資料庫中,並對其進行認證。如果它不存在,我們將建立一個新的記錄來代表該使用者:
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
Route::get('/auth/callback', function () {
$googleUser = Socialite::driver('google')->user();
Create the user if it does not exist
Update the user if it exists
Check for google_id in database
$user = User::updateOrCreate([
'google_id' => $googleUser->id,
'name' => $googleUser->name,
'email' => $googleUser->email,
'google_token' => $googleUser->token,
'google_refresh_token' => $googleUser->refreshToken,
Authenticates the user using the Auth facade
return redirect('/dashboard');
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
Route::get('/auth/callback', function () {
/*
Get the user
*/
$googleUser = Socialite::driver('google')->user();
/*
Create the user if it does not exist
Update the user if it exists
Check for google_id in database
*/
$user = User::updateOrCreate([
'google_id' => $googleUser->id,
], [
'name' => $googleUser->name,
'email' => $googleUser->email,
'google_token' => $googleUser->token,
'google_refresh_token' => $googleUser->refreshToken,
]);
/*
Authenticates the user using the Auth facade
*/
Auth::login($user);
return redirect('/dashboard');
});
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
Route::get('/auth/callback', function () {
/*
Get the user
*/
$googleUser = Socialite::driver('google')->user();
/*
Create the user if it does not exist
Update the user if it exists
Check for google_id in database
*/
$user = User::updateOrCreate([
'google_id' => $googleUser->id,
], [
'name' => $googleUser->name,
'email' => $googleUser->email,
'google_token' => $googleUser->token,
'google_refresh_token' => $googleUser->refreshToken,
]);
/*
Authenticates the user using the Auth facade
*/
Auth::login($user);
return redirect('/dashboard');
});
如果我們想限制使用者的訪問範圍,我們可以使用 scopes
方法,我們將在認證請求中包括該方法。這將把所有以前指定的作用域與指定的作用域合併。
另一種方法是使用 setScopes
方法,它可以覆蓋所有其他現有的作用域:
use Laravel\Socialite\Facades\Socialite;
return Socialite::driver('google')
->scopes(['read:user', 'write:user', 'public_repo'])
return Socialite::driver('google')
->setScopes(['read:user', 'public_repo')
use Laravel\Socialite\Facades\Socialite;
return Socialite::driver('google')
->scopes(['read:user', 'write:user', 'public_repo'])
->redirect();
return Socialite::driver('google')
->setScopes(['read:user', 'public_repo')
->redirect();
use Laravel\Socialite\Facades\Socialite;
return Socialite::driver('google')
->scopes(['read:user', 'write:user', 'public_repo'])
->redirect();
return Socialite::driver('google')
->setScopes(['read:user', 'public_repo')
->redirect();
現在我們知道了一切,知道了如何在回撥後獲得一個使用者,讓我們看看我們可以從中獲得的一些資料。
OAuth1使用者有 token
和 tokenSecret
:
$user = Socialite::driver('google')->user();
$tokenSecret = $user->tokenSecret;
$user = Socialite::driver('google')->user();
$token = $user->token;
$tokenSecret = $user->tokenSecret;
$user = Socialite::driver('google')->user();
$token = $user->token;
$tokenSecret = $user->tokenSecret;
OAuth2提供 token
, refreshToken
和 expiresIn
:
$user = Socialite::driver('google')->user();
$refreshToken = $user->refreshToken;
$expiresIn = $user->expiresIn;
$user = Socialite::driver('google')->user();
$token = $user->token;
$refreshToken = $user->refreshToken;
$expiresIn = $user->expiresIn;
$user = Socialite::driver('google')->user();
$token = $user->token;
$refreshToken = $user->refreshToken;
$expiresIn = $user->expiresIn;
OAuth1和OAuth2都提供 getId
, getNickname
, getName
, getEmail
和 getAvatar
:
$user = Socialite::driver('google')->user();
$user = Socialite::driver('google')->user();
$user->getId();
$user->getNickName();
$user->getName();
$user->getEmail();
$user->getAvatar();
$user = Socialite::driver('google')->user();
$user->getId();
$user->getNickName();
$user->getName();
$user->getEmail();
$user->getAvatar();
如果我們想從令牌(OAuth 2)或令牌和祕密(OAuth 1)中獲取使用者的詳細資訊,sanctum提供了兩種方法:userFromToken
和 userFromTokenAndSecret
:
use Laravel\Socialite\Facades\Socialite;
$user = Socialite:;driver('google')->userFromToken($token);
$user = Socialite::driver('twitter')->userFromTokenAndSecret($token, $secret);
use Laravel\Socialite\Facades\Socialite;
$user = Socialite:;driver('google')->userFromToken($token);
$user = Socialite::driver('twitter')->userFromTokenAndSecret($token, $secret);
use Laravel\Socialite\Facades\Socialite;
$user = Socialite:;driver('google')->userFromToken($token);
$user = Socialite::driver('twitter')->userFromTokenAndSecret($token, $secret);
Laravel Sanctum
Laravel Sanctum是一個輕量使用者認證系統,適用於SPAs(單頁應用程式)和移動應用程式。它允許使用者生成多個具有特定範圍的API令牌。這些範圍指定了一個令牌所允許的行動。
使用方法
Sanctum可以用來向使用者發放API令牌,而不需要OAuth的複雜機制。這些令牌通常有很長的過期時間,比如幾年,但使用者可以在任何時候撤銷並重新生成。
安裝和配置
我們可以通過composer來安裝它:
composer require laravel/sanctum
composer require laravel/sanctum
composer require laravel/sanctum
而且我們必須釋出配置和遷移檔案:
php artisan vendor:publish –provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan vendor:publish –provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan vendor:publish –provider="Laravel\Sanctum\SanctumServiceProvider"
現在我們已經生成了新的遷移檔案,我們必須對它們進行遷移:
php artisan migrate </code> or <code> php artisan migrate:fresh
php artisan migrate </code> or <code> php artisan migrate:fresh
php artisan migrate </code> or <code> php artisan migrate:fresh
如何簽發API令牌
在簽發令牌之前,我們的使用者模型應該使用Laravel\Sanctum\HasApiTokens特性:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticable
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticable
{
use HasApiTokens;
}
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticable
{
use HasApiTokens;
}
當我們有了使用者, 我們可以通過呼叫 createToken
方法來發行一個令牌,它將返回一個Laravel/Sanctum/NewAccessToken例項。
我們可以呼叫NewAccessToken例項的 plainTextToken
方法來檢視令牌的SHA-256純文字值。
Laravel使用者認證的技巧和最佳實踐
使其他裝置上的會話無效
正如我們之前所討論的,當使用者登出時,使會話無效是至關重要的,但這也應該作為一個選項提供給所有擁有的裝置。
這個功能通常在使用者改變或更新他們的密碼時使用,而我們想從任何其他裝置上使他們的會話失效。
有了Auth facade,這是個很容易實現的任務。考慮到我們使用的路由有 auth
和 auth.session middleware
,我們可以使用facade的 logoutOtherDevices
靜態方法:
Route::get('/logout', [LogoutController::class, 'invoke'])
->middleware(['auth', 'auth.session']);
Route::get('/logout', [LogoutController::class, 'invoke'])
->middleware(['auth', 'auth.session']);
Route::get('/logout', [LogoutController::class, 'invoke'])
->middleware(['auth', 'auth.session']);
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);
使用Auth::routes()配置
Auth facade的routes方法只是一個幫助工具,用於生成使用者認證所需的所有路線。
這些路由包括登入(Get, Post)、登出(Post)、註冊(Get, Post)和密碼重置/電子郵件(Get, Post)。
當你在facade上呼叫方法時,它會做以下工作:
public static fucntion routes(array $options = [])
if (!static::$app->providerIsLoaded(UiServiceProvider::class)) {
throw new RuntimeException('In order to use the Auth:;routes() method, please install the laravel/ui package.');
static::$app->make('router')->auth($options);
public static fucntion routes(array $options = [])
{
if (!static::$app->providerIsLoaded(UiServiceProvider::class)) {
throw new RuntimeException('In order to use the Auth:;routes() method, please install the laravel/ui package.');
}
static::$app->make('router')->auth($options);
}
public static fucntion routes(array $options = [])
{
if (!static::$app->providerIsLoaded(UiServiceProvider::class)) {
throw new RuntimeException('In order to use the Auth:;routes() method, please install the laravel/ui package.');
}
static::$app->make('router')->auth($options);
}
我們感興趣的是在路由器上呼叫靜態方法時會發生什麼。由於facades的工作方式,這可能很棘手,但下面呼叫的方法是這樣的:
Register the typical authentication routes for an application.
public function auth(array $options = [])
// Authentication Routes...
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$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) {
// Email Verification Routes...
if ($options['verify'] ?? false) {
$this->emailVerification();
/**
Register the typical authentication routes for an application.
@param array $options
@return void
*/
public function auth(array $options = [])
{
// Authentication Routes...
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$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();
}
// Email Verification Routes...
if ($options['verify'] ?? false) {
$this->emailVerification();
}
}
/**
Register the typical authentication routes for an application.
@param array $options
@return void
*/
public function auth(array $options = [])
{
// Authentication Routes...
$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
$this->post('login', 'Auth\LoginController@login');
$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();
}
// Email Verification Routes...
if ($options['verify'] ?? false) {
$this->emailVerification();
}
}
預設情況下,它生成了除電子郵件驗證以外的所有路由。我們將永遠有登入和登出路線,但其他的路線我們可以通過選項陣列來控制。
如果我們想只有登入/登出和註冊,我們可以傳遞以下選項陣列:
$options = ["register" => true, "reset" => false, "verify" => false];
$options = ["register" => true, "reset" => false, "verify" => false];
$options = ["register" => true, "reset" => false, "verify" => false];
保護路由和自定義守衛
我們要確保一些路由只能由經過認證的使用者訪問,可以通過新增在路由門面上呼叫中介軟體方法或在其上連鎖中介軟體方法來快速完成:
Route::middleware('auth')->get('/user', function (Request $request) {
Route::get('/user', function (Request $request) {
Route::middleware('auth')->get('/user', function (Request $request) {
return $request->user();
});
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth');
Route::middleware('auth')->get('/user', function (Request $request) {
return $request->user();
});
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth');
這個防護措施確保傳入的請求得到驗證。
密碼確認
為了增加網站的安全性,你經常想在繼續執行其他任務之前確認使用者的密碼。
我們必須從確認密碼檢視中定義一個路由來處理這個請求。它將驗證並將使用者重定向到他們預定的目的地。同時,我們將確保我們的密碼在會話中出現確認。預設情況下,密碼必須每三小時重新確認一次,但這可以在配置檔案config/auth.php中改變:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
Route::post('/confirm-password', function (Request $request) {
if (!Hash::check($request->password, $request->user()->password)) {
return back()->withErrors([
'password' => ['The provided password does not match our records.']
$request->session()->passwordConfirmed();
return redirect()->intended();
})->middleware(['auth']);
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
Route::post('/confirm-password', function (Request $request) {
if (!Hash::check($request->password, $request->user()->password)) {
return back()->withErrors([
'password' => ['The provided password does not match our records.']
]);
}
$request->session()->passwordConfirmed();
return redirect()->intended();
})->middleware(['auth']);
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;
Route::post('/confirm-password', function (Request $request) {
if (!Hash::check($request->password, $request->user()->password)) {
return back()->withErrors([
'password' => ['The provided password does not match our records.']
]);
}
$request->session()->passwordConfirmed();
return redirect()->intended();
})->middleware(['auth']);
Authenticable合約
位於Illuminate/Contracts\Auth的Authenticable合約定義了UserProvider介面應該實現的blueprint:
namespace Illuminate\Contracts\Auth;
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassord();
public function getRememberToken();
public function setRememberToken($value);
public function getrememberTokenName();
namespace Illuminate\Contracts\Auth;
interface Authenticable
{
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassord();
public function getRememberToken();
public function setRememberToken($value);
public function getrememberTokenName();
}
namespace Illuminate\Contracts\Auth;
interface Authenticable
{
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassord();
public function getRememberToken();
public function setRememberToken($value);
public function getrememberTokenName();
}
該介面允許使用者認證系統與任何實現它的 “user” 類一起工作。
無論使用什麼ORM或儲存層, 這都是可行的. 預設情況下, Laravel有一個App\Models\User實現了這個介面, 這也可以在配置檔案中看到:
'model' => App\Models\User::class,
return [
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
];
return [
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
],
];
身份認證事件
在整個認證過程中,有很多事件被派發。
根據你的目標,你可以在 EventServiceProvider
中給這些事件附加監聽器。

為我們的認證服務生成的Laravel監聽器的列表
快速建立新使用者
建立一個新的使用者可以通過App\User快速完成:
$user->password = Hash::make('strong_password');
$user->email = 'test-email@user.com';
$user->name = 'Username';
$user = new App\User();
$user->password = Hash::make('strong_password');
$user->email = 'test-email@user.com';
$user->name = 'Username';
$user->save();
$user = new App\User();
$user->password = Hash::make('strong_password');
$user->email = 'test-email@user.com';
$user->name = 'Username';
$user->save();
或者通過User facade上的建立靜態方法:
'password' => Hash::make('strong-password'),
'email' => 'test-email@user.com',
User::create([
'password' => Hash::make('strong-password'),
'email' => 'test-email@user.com',
'name' => 'username'
]);
User::create([
'password' => Hash::make('strong-password'),
'email' => 'test-email@user.com',
'name' => 'username'
]);
小結
Laravel生態系統有很多啟動工具包,可以讓你的應用程式啟動並執行一個使用者認證系統,如Breeze和Jetstream。它們是高度可定製的,因為程式碼是在我們這邊生成的,我們可以隨心所欲的修改它,如果需要的話,可以把它作為一個藍本。
關於使用者認證和它的複雜性,有很多安全問題,但所有這些都可以通過Laravel提供的工具輕鬆解決。這些工具是高度可定製的,而且易於使用。
評論留言