【Laravel實戰】實作Laravel會員驗證,看這一篇就夠了
這個實作將使用 Jetstream 這個 Starter Kit 來進行快速開發
如果你想要了解更多關於 Jetstream 與其他驗證套件的比較,歡迎參考 3驗證系統開箱指南
功能介紹
Jetstream 內建了以下驗證常用的功能,讓你能夠快速實作:
登入表單
預設是使用 email 欄位來進行驗證登入,這張圖是我自定義進行的修改
註冊表單
預設是沒有 username 欄位的,這張圖是我自定義進行的修改
雙重驗證
這功能開啟後可由用戶自行決定是否要使用
重置密碼
電子郵件驗證
啟用此功能後,會在用戶完成註冊後進行 Email 驗證,必須完成驗證才能進入網站
準備Jetstream專案
新專案
Step1.下載&安裝套件
如果你正好要一併新增專案的話,可以在新增專案時順帶安裝 Jetstream
開啟 Terminal,輸入以下指令
laravel new 專案名稱 --jet
接著畫面會以問答的方式來詢問你要如何進行設定。
- 問題1:你要使用哪一種前端框架? livewire 還是 inertia
- 問題2:應用是否需要使用 teams 機制
這篇實戰將以對後端工程師最友善的 Livewire 來進行介紹,獨立進行開發沒有團隊,所以分別回答 0 以及 no
舊專案
如果你的專案已經存在,還是可以使用 Jetstream ,只是有些安裝步驟要自己作,也不難
Step 1.下載套件
開啟 Terminal,切換到專案資料夾目錄,輸入以下指令:
composer require laravel/jetstream
Step 2.安裝套件
輸入以下指令:
php artisan jetstream:install livewire
記得務必要輸入任何一種前端框架,比如 livewire,否則可是會報錯的!
如果你偏好使用 inertia 請把上方指令的 livewire 改成 inertia
安裝Jetstream
Step 1.安裝&編譯依賴前端套件
開啟 Terminal,輸入以下指令:
這一段指令會安裝所有依賴的前端套件,就類似安裝後端套件的 composer install
npm install
這一段指令會編譯所有依賴套件檔案,但不破壞其原本程式碼結構
npm run build
如果你的專案是 Laravel 9 ,可能會出現 Error: Cannot find module 'node:path' 的錯誤,解決關鍵是升級你的 Node.js 版本。具體作法是下載 Node.js 最新版本(v.18.10 以上)後安裝,並且到設定的進階環境變數,找到 PATH 去加入 Node.js 資料夾所在(C:\Program Files\nodejs),完成後關閉 CMD重開,輸入 node -v 確認版本是否升級到 v.18 ,順利的話問題就解決了
Step2.建立資料庫&生成資料表
別忘了要建立一個專案要使用的資料庫,並把帳號密碼等相關設定寫在.env檔裏頭
完成資料庫建立後,開啟 Terminal,輸入以下指令:
php artisan migrate
當一切執行完畢之後就完成了套件的下載以及安裝了,非常簡單
Step3(非必須).如果應用的網域並非根路徑,有需要進行 Livewire 設定
作法是使用以下指令來建立 livewire 設定
php artisan livewire:publish --config
php artisan livewire:publish --assets
接著設定 config\livewire.php 裏頭的 asset_url 如下所示:
'asset_url' => 'http://localhost:6080/jetstream3/public',
基本自定義驗證
雖然 Jetstream 已經替你完成了驗證系統的開發,但你還是可以有很大的彈性來進行修改
修改視圖
所有的視圖都被放在 resources/views/auth 資料夾內,如下表,你可以根據需要來修改
檔名 | 對應畫面 |
---|---|
confirm-password.blade.php | 確認密碼 |
forgot-password.blade.php | 忘記密碼 |
login.blade.php | 登入頁面 |
register.blade.php | 註冊頁面 |
reset-password.blade.php | 重設密碼 |
two-factor-challenge.blade.php | 二階段認證 |
verify-email.blade.php | 驗證Email |
修改邏輯
所有的後端驗證邏輯由 Laravel Fortify 提供支持,檔案存放於 app/Actions/Fortify 資料夾內,你可以根據下表來找到程式碼進行修改
檔名 | 對應功能 |
---|---|
CreateNewUser.php | 新增使用者,用於註冊時 |
PasswordValidationRules.php | 密碼驗證規則 |
ResetUserPassword.php | 重設使用者密碼 |
UpdateUserPassword.php | 變更使用者密碼 |
UpdateUserProfileInformation.php | 變更使用者資料 |
修改設定
所有的驗證設定都被存放於 config/fortify.php ,你可以根據專案需要來開啟或關閉以下功能:
'features' => [
Features::registration(), //註冊功能
Features::resetPasswords(), //重設密碼
Features::emailVerification(), //Email驗證
Features::updateProfileInformation(), //更新使用者資訊
Features::updatePasswords(), //更新密碼
Features::twoFactorAuthentication([ //二階段認證
'confirmPassword' => true,
]),
],
比如當你把 Features::resetPasswords() 這一行註解起來之後,就會發現登入頁面不再提供忘記密碼的功能囉
修改登入驗證邏輯
雖然 Jetstream 已經完成了登入驗證的邏輯,也就是比對 username (預設是email欄位) 以及密碼是否正確,但你還是可以自己修改,只要編輯 app/Providers/FortifyServiceProvider.php 即可,如下範例所示:
//app\Providers\FortifyServiceProvider.php
namespace App\Providers;
...
class FortifyServiceProvider extends ServiceProvider
{
public function boot()
{
...
Fortify::authenticateUsing(function (Request $request) {
//撰寫你的登入驗證邏輯,最終必須回傳登入者的模型才表示登入成功
$user = User::where('email', $request->email)->first();
if ($user && Hash::check($request->password, $user->password)) {
return $user;
}
});
}
}
修改個人資料管理
Jetstream 內建有提供了使用者個人資料管理功能,允許使用者能夠便利的更新姓名,電子郵件地址和大頭照
視圖
個人資料管理功能視圖位於:resources/views/profile/update-profile-information-form.blade.php
但假如你用的是 Inertia ,則 vue 檔案可以在以下位置找到:resources/js/Pages/Profile/UpdateProfileInformationForm.vue
程式邏輯
如果你需要修改使用者更新個人資料的邏輯,可編輯以下檔案:
app/Actions/Fortify/UpdateUserProfileInformation.php
如果你想開啟使用者大頭照功能,只需要到 config/jetstream.php
設定檔去移除 Features::profilePhotos() 的註解即可
//config\jetstream.php
'features' => [
Features::profilePhotos(),
//Features::api(),
// Features::teams(),
],
修改登入後轉址連結
開啟 app/Providers/RouteServiceProvider.php
,修改 HOME 常數到新的路徑即可
//app\Providers\RouteServiceProvider.php
namespace App\Providers;
class RouteServiceProvider extends ServiceProvider
{
//用戶登入後要轉址的頁面
public const HOME = '/dashboard';
}
常用自定義需求
改用帳號欄位來進行登入
Step 1.修改登入視圖
開啟 resources/views/auth/login.blade.php
,將視圖內的 email 輸入項改成 username
//resources/views/auth/login.blade.php
<x-guest-layout>
<x-jet-authentication-card>
<x-slot name="logo">
<x-jet-authentication-card-logo />
</x-slot>
<x-jet-validation-errors class="mb-4" />
@if (session('status'))
<div class="mb-4 font-medium text-sm text-green-600">
{{ session('status') }}
</div>
@endif
<form method="POST" action="{{ route('login') }}">
@csrf
<div>
<x-jet-label for="username" value="帳號" />
<x-jet-input id="username" class="block mt-1 w-full" type="text" name="username"
:value="old('username')"
required autofocus />
</div>
<div class="mt-4">
<x-jet-label for="password" value="{{ __('Password') }}" />
<x-jet-input id="password" class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" />
</div>
<div class="block mt-4">
<label for="remember_me" class="flex items-center">
<x-jet-checkbox id="remember_me" name="remember" />
<span class="ml-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
</label>
</div>
<div class="flex items-center justify-end mt-4">
@if (Route::has('password.request'))
<a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('password.request') }}">
{{ __('Forgot your password?') }}
</a>
@endif
<x-jet-button class="ml-4">
{{ __('Log in') }}
</x-jet-button>
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>
Step 2.修改驗證設定
修改驗證設定檔 config/fortify.php
裡頭的 username 設定,改成如下所示:
'username' => 'username',
追加註冊欄位
Step 1.修改註冊視圖
這裡示範追加 username 欄位,開啟 resources/views/auth/register.blade.php
,加入 username 輸入項,如下範例所示:
//resources/views/auth/register.blade.php
<x-guest-layout>
...
<form method="POST" action="{{ route('register') }}">
@csrf
<div>
<x-jet-label for="username" value="{{ __('Username') }}" />
<x-jet-input id="username" class="block mt-1 w-full" type="text" name="username" :value="old('username')" required
autofocus autocomplete="username" />
</div>
<div>
<x-jet-label for="name" value="{{ __('Name') }}" />
<x-jet-input id="name" class="block mt-1 w-full" type="text" name="name" :value="old('name')" required autofocus autocomplete="name" />
</div>
</form>
</x-jet-authentication-card>
</x-guest-layout>
Step 2.修改新增使用者功能
開啟 app/Actions/Fortify/CreateNewUser.php
,修改共兩處的程式碼
//app\Actions\Fortify\CreateNewUser.php
namespace App\Actions\Fortify;
class CreateNewUser implements CreatesNewUsers
{
use PasswordValidationRules;
public function create(array $input)
{
Validator::make($input, [
//增加這一行
'username' => ['required', 'string', 'max:255'],
'name' => ['required', 'string', 'max:255'],
...
])->validate();
return User::create([
//增加這一行
'username' => $input['username'],
'name' => $input['name'],
...
]);
}
}
Step 3.擴充資料表
因為使用者資料存放於 users 表格內,因此需要擴增一個名為 username 的欄位
在這裡我們新增一個 Migration 檔案來執行追加欄位的作業。開啟 Terminal,輸入以下指令:
php artisan make:migration add_username_users_table --table=users
開啟剛生成的 Migration 檔案,將內容修改如下範例所示:
//database\migrations\xxxx_xx_xx_xxxxxx_add_username_users_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUsernameUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('username',30)->unique();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('username');
});
}
}
編輯完後執行 migrate 來完成欄位新增
php artisan migrate
Step 4.加入User白名單
如果沒有把 username 加入白名單欄位的話,將無法正常的將 username 的值寫入資料庫中
開啟 app/Models/User.php
,將 username 加入 $fillable 陣列裡頭
//app\Models\User.php
protected $fillable = [
'username', //加入這一行
'name',
'email',
'password',
];
如果有使用 Voyager套件來製作後台功能的話,還需要在
User.php
加上以下內容才不會出現角色相關錯誤
//app\Models\User.php
use TCG\Voyager\Traits\VoyagerUser;
class User extends Authenticatable
{
use VoyagerUser;
...
}
開啟註冊時 Email 驗證功能
你可以讓使用者註冊好之後,必須要先完成 Email 驗證動作之後才可以進入網頁
開啟這功能會用到 Email 發信,請務必確認 .env 有關 Email 發信的設定是正確的
//.env
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=你的EMAIL帳號
MAIL_PASSWORD=你的EMAIL密碼
MAIL_ENCRYPTION=null
Step 1.修改 fortify 設定檔
開啟 config/fortify.php 設定檔,移除 Features::emailVerification()
前面的註解
//config\fortify.php
'features' => [
...
Features::emailVerification(),
...
],
Step 2.修改 User 模型
接著需要為用戶模型 User 追加實作 MustVerifyEmail,如下範例:
//app\Models\User.php
namespace App\Models;
class User extends Authenticatable implements MustVerifyEmail
加入登出按鈕
在要登出的地方使用以下程式碼
<form method="POST" action="{{ route('logout') }}">
@csrf
<a href="{{ route('logout') }}"
onclick="event.preventDefault();
this.closest('form').submit();">
<span>登出</span>
</a>
</form>
保護路由需要登入才能訪問
將要保護的路由放入以下的群組裏頭
//routes\web.php
Route::middleware(['auth'])->group(function () {
//要驗證才能訪問的路由
Route::get('/checkout','App\Http\Controllers\SiteController@renderCheckoutPage');
Route::post('/checkout','App\Http\Controllers\SiteController@checkout');
Route::get('/shop/cart','App\Http\Controllers\SiteController@renderCartPage');
Route::get('/shop/addcart/{product}','App\Http\Controllers\SiteController@addCart');
});