實作Laravel 註冊、登入搭配JWT

2023/09/30閱讀時間約 29 分鐘

本篇純粹紀錄實作流程,以方便未來可以照此版繼續優化改進作法,這篇會使用Laravel 9版本並搭配Boostrap 5來做開發。

發現將每一次的實作作筆記,回頭再看的時候,就可以發現實作差異並進行改正,沒搞懂的底層操作也能在覆盤的時候理解,建議大家都要筆記自己的實作流程。

會員註冊設計

我們將用vite編譯工具來幫我們產生JS and CSS,詳細配置可以看一下先前的文章。 實作 Laravel 9 改用 vite 作為前端編譯檔案配置

首先先設計註冊畫面,創建一個命名為signUp.blade.php,附上範例code

@extends('layouts.app') 
@section('content')
<div class="row d-flex justify-content-center align-items-center h-100 vh-100">
<div class="col-12 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-2-strong" style="border-radius: 1rem;">
<div class="card-body p-5">
<form method="POST" action="{{ route('register') }}">
@csrf
<h3 class="mb-5 text-center">會員註冊</h3>

<div class="form-outline mb-4">
<label for="account" class="form-label">會員帳號</label>
<input
id="account"
type="text"
class="form-control form-control-lg"
placeholder="Account"
aria-label="Account"
aria-describedby="basic-addon1"
name="account"
/>
</div>

<div class="form-outline mb-4">
<label for="userName" class="form-label">會員名稱</label>
<input
id="userName"
type="text"
class="form-control form-control-lg"
placeholder="UserName"
aria-label="userName"
aria-describedby="basic-addon1"
name="userName"
/>
</div>

<div class="form-outline mb-4">
<label for="password" class="form-label">會員密碼</label>
<input
id="password"
type="password"
id="password"
class="form-control form-control-lg"
placeholder="Password"
aria-label="Password"
aria-describedby="basic-addon1"
name="password"
/>
</div>

<div class="form-outline mb-4">
<label for="password-confirm" class="form-label">確認密碼</label>
<input
id="password-confirm"
type="password"
class="form-control form-control-lg"
name="password_confirmation"
required
autocomplete="new-password"
placeholder="PasswordConfirm"
/>
</div>

<!-- button -->
<div class="d-grid gap-2">
<button class="btn btn-primary btn-lg" type="submit">
REGISTER
</button>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection

畫面長這樣(很簡陋的東西XDDDD)

raw-image

接著撰寫Controller邏輯

php artisan make:controller AuthController​

編寫取得signUp.blade.php View跟註冊 register邏輯方法

註:這邊function命名方式採用camelCase,駝峰命名方式,又稱小駝峰命名方式(lowerCamelCase)

<?php

namespace App\Http\Controllers;

use Exception;
use App\Models\User;
use Illuminate\Support\Str;
use App\Http\Requests\LoginRequest;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\RegisterRequest;

class AuthController extends Controller
{
public function signUp()
{
return view('signUp');
}

public function register(RegisterRequest $request)
{
$uid = Str::uuid();
$account = $request->request->get('account');
$userName = $request->request->get('userName');
$password = $request->request->get('password');

User::create([
'uid' => $uid,
'account' => $account,
'userName' => $userName,
'password' => bcrypt($password),
]);

return redirect()->route('signIn');
}
}

這邊的Request改採用Form Request來編寫,方便以後寫特定的Rules。

php artisan make:request RegisterRequest
raw-image

再來修改原本的migration table User Table的部分,修改部分為綠色code的樣子,主要是我的id想要用成uid的方式,email改為允許為null,主鍵改成uid,配置完成執行migrate

php artisan migrate
raw-image

接著配置User Model

<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;

protected $primaryKey = 'uid';
protected $keyType = 'string';

protected $guarded = [];

/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'uid',
'userName',
'account',
'email',
'password',
];

/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];

/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}

配置路由web.php檔案,而路由檔支持的寫法有很多種,詳下圖

raw-image

接下來確認新增都沒問題就大功完成註冊的部分~

raw-image

會員登入設計

會員登入的畫面拿註冊畫面來改,一樣先創建signIn.blade.php畫面

@extends('layouts.app')

@section('content')
<div class="row d-flex justify-content-center align-items-center h-100 vh-100">
<div class="col-12 col-md-8 col-lg-6 col-xl-5">
<div class="card shadow-2-strong" style="border-radius: 1rem;">
<div class="card-body p-5">
<form action="{{ route('login') }}" method="post" enctype="multipart/form-data">
@csrf
<h3 class="mb-5 text-center">LOGIN</h3>

<div class="form-outline mb-4">
<label for="account" class="form-label">會員帳號</label>
<input id="account" type="text" class="form-control form-control-lg" placeholder="Account"
aria-label="Account" aria-describedby="basic-addon1" name="account">
</div>

<div class="form-outline mb-4">
<label for="password" class="form-label">會員密碼</label>
<input id="password" type="password" id="password" class="form-control form-control-lg"
placeholder="Password" aria-label="Password" aria-describedby="basic-addon1" name="password">
</div>

<!-- Checkbox -->
{{-- <div class="form-check d-flex justify-content-start mb-4">
<input class="form-check-input" type="checkbox" value="" id="form1Example3" />
<label class="form-check-label" for="form1Example3"> Remember password </label>
</div> --}}


<!-- button -->
<div class="d-grid gap-2">
<a type="submit" id="create_form" class="btn btn-primary btn-lg">Login</a>
{{-- <button class="btn btn-primary btn-lg" type="submit" id="create_form">Login</button> --}}
<hr class="my-2">
<button class="btn btn-lg btn-block btn-primary" style="background-color: #dd4b39;"
type="submit"><i class="fab fa-google me-2"></i> Sign in with google</button>
<hr class="my-2">
<button class="btn btn-lg btn-block btn-primary mb-2" style="background-color: #3b5998;"
type="submit"><i class="fab fa-facebook-f me-2"></i>Sign in with facebook</button>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection




安裝JWT並產生Token

這邊使用tymon/jwt-auth 套件,並根據使用文檔配置,來設定我們的Private Key,並搭配 firebase/php-jwt,來創建我們的Token

composer require tymon/jwt-auth

配置vendor,接著會產生config/jwt.php檔案,有些設定可以在這邊改

php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"

產生金鑰

php artisan jwt:secret

安裝firebase/php-jwt

composer require firebase/php-jwt

接著開始寫產生Token的程式邏輯,這邊創建Services/AuthService.php 檔案,並定義一個encode方法

raw-image

接著修改AuthController檔案,增加login方法,驗證登入帳密及產生Token,並由Service端把token塞到cookie,方便前端取用。

Token在前端保存有多種方式,額外再寫一篇補充說明,看完一些文件說明,大致上沒有一定需要怎麼做🧐

<?php

namespace App\Http\Controllers;

use Exception;
use App\Models\User;
use Illuminate\Support\Str;
use App\Services\AuthService;
use App\Http\Requests\LoginRequest;
use Illuminate\Support\Facades\Hash;
use App\Http\Requests\RegisterRequest;

class AuthController extends Controller
{
private AuthService $authService;

public function __construct(
AuthService $authService
) {
$this->authService = $authService;
}

public function signUp()
{
return view('signUp');
}

public function signIn()
{
return view('signIn');
}

public function register(RegisterRequest $request)
{
$uid = Str::uuid();
$account = $request->request->get('account');
$userName = $request->request->get('userName');
$password = $request->request->get('password');

User::create([
'uid' => $uid,
'account' => $account,
'userName' => $userName,
'password' => bcrypt($password),
]);

return redirect()->route('signIn');
}

public function login(LoginRequest $request)
{
$account = $request->request->get('account');
$password = $request->request->get('password');

$userData = User::where('account', $account)->first();

if (!$userData || !Hash::check($password, $userData->password)) {
throw new Exception('密碼錯誤');
}

$token = $this->authService->encode($userData);

$minutes = 5;
return response()->json([
'status' => 'success',
'data' => [
'access_token' => $token,
'token_type' => 'bearer',
'expired_at' => now()->addMinutes(config('jwt.ttl'))->timestamp
]
])->withCookie(cookie('token', $token, $minutes));
}

}

新增login.js檔案,並使用AJAX處理,在登入成功確認response的結果是否有Token。

raw-image

接著測試登入結果有正常取得Token結果

raw-image
raw-image


















13會員
37內容數
學涯無止境,透過每日or每週模仿學習筆記,不管是哪些領域也好,總有一天也可以從菜雞變小雞
留言0
查看全部
發表第一個留言支持創作者!
從 Google News 追蹤更多 vocus 的最新精選內容