Lumen 是 Laravel 衍生出來的微型框架,去除掉 View 的部分 及相當多在 Laravel 載入的部分,主要用來當作 API 伺服器用,讓前後端分離的網站提升整體的速度。
參考資料來源:
Lumen 官方網站 https://lumen.laravel.com/
JWT 官方網站 https://jwt-auth.readthedocs.io/
Lumen Generator 套件 https://github.com/flipboxstudio/lumen-generator
安裝 Lumen
composer create-project --prefer-dist laravel/lumen LumenJWTAuth
由於 Lumen 8.x 預設安裝非常的乾淨,少了 Laravel 非常多東西,包括原來好用的一些 make 指令。
composer require flipbox/lumen-generator
產生 APP_KEY
由於安裝了 Lumen Generator 可以很輕鬆的直接使用 make 指令來產生 APP_KEY
php artisan key:generate
安裝 JWT
composer require tymon/jwt-auth
修改 bootstrap\app.php
// 反註解下面這幾行,Lumen 8.x 預設已經註解掉
$app->withEloquent();
$app->register(App\Providers\AuthServiceProvider::class);
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
// 新增下面這行
$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);
產生 JWT 的密鑰
php artisan jwt:secret
建立 User migration 及 假資料
由於 Lumen 8.x 預設安裝後並沒有 user 的 migration 需自己手動建立。(提供了 User 的 Model 及 Factory 竟然沒提供 migration 蠻怪異的。)
php artisan make:migration create_users_table
修改 database\migrations\時間序列_create_users_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('email')->unique()->comment('電子郵件');
$table->string('password')->comment('密碼');
$table->timestamp('email_verified_at')->nullable();
$table->string('name')->comment('姓名');
$table->boolean('gender')->default(0)->comment('性別'); //1男 2女 0未知
$table->string('tel')->nullable()->comment('電話');
$table->string('address')->nullable()->comment('地址');
$table->string('avatar',500)->nullable()->comment('頭像'); //頭像功能,可為空值
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
建立 users 資料表
php artisan migrate
修改 Models\User.php 的 fillable 資料
protected $fillable = [
'name', 'email','gender','tel','address','avatar',
];
修改 database\factories\UserFactory.php
<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'gender' => mt_rand(1, 2),
'email_verified_at' => date('Y-m-d H:i:s'),
'password' => '$2y$10$92IXUNpsdO0rOQ5byMi.Ye4oKwea3Ro9llC/.og/at2.uheWG/igi',
'address' => $this->faker->address,
'tel' => $this->faker->phoneNumber,
];
}
}
修改 database\seeders\DatabaseSeeder.php
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\User as UserEloquent;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// $this->call('UsersTableSeeder');
//建立一筆使用者
UserEloquent::create([
'name' => '使用者',
'gender' => 1,
'email' => 'user@mail.com',
'email_verified_at' => date('Y-m-d H:i:s'),
'password' => app('hash')->make('user'),
'address' => '地球',
'tel' => '0123456789',
]);
//建立一筆訪客
UserEloquent::create([
'name' => '訪客',
'gender' => 2,
'email' => 'guest@mail.com',
'password' => app('hash')->make('user'),
'address' => '火星',
'tel' => '9876543210',
]);
//在users資料表建立18筆
UserEloquent::factory()->count(18)->create();
}
}
建立假資料
php artisan db:seed
修改 Models\User.php
參考 JWT 說明 加入 JWT 相關的 function
<?php
namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Lumen\Auth\Authorizable;
//使用 JWT
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Model implements JWTSubject, AuthenticatableContract, AuthorizableContract
{
use Authenticatable, Authorizable, HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email','gender','tel','address','avatar',
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
'password',
];
// Rest omitted for brevity
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* @return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* @return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
建立 config\auth.php
Lumen 8.x 預設安裝並沒有 config 這個目錄,自行建立 config 目錄,並從 vendor\laravel\lumen-framework\config 目錄中複製 auth.php 到 config 目錄中。
修改 config\auth.php
//修改 driver 使用 jwt 及 provider 使用 users 資料表
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users'
]
],
定義路由
// 使用者登入登出及查詢自己
$router->group([
'prefix' => '/',
'namespace' => 'Api',
], function () use ($router) {
$router->post('login', 'UserLoginController@login');
$router->get('me', 'UserLoginController@me');
$router->get('logout', 'UserLoginController@logout');
});
建立 UserLoginController
php artisan make:controller Api\UserLoginController
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class UserLoginController extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
//除了 login 其餘 function 都要經過 api 的 middleware 檢查
$this->middleware('auth:api', ['except' => ['login']]);
}
/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login(Request $request)
{
//驗證
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|min:4',
]);
//透過Auth取得JWT token
if (! $token = auth()->attempt($request->all())) {
return response()->json(['error' => '授權失敗'], 401);
}
//將token拋出
return $this->respondWithToken($token);
}
/**
* Get the authenticated User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth()->user());
}
/**
* Log the user out (Invalidate the token).
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
//登出並清除token
auth()->logout();
return response()->json(['message' => 'Successfully logged out'], 200);
}
/**
* Refresh a token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth()->refresh());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
return response()->json([
'user' => auth()->user(), //將使用者資料一起帶出
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * 60
]);
}
}
使用 Postman 測試
成品同步放在我的 GitHub 上.