Lumen 8.0 使用 Jwt 認證的 Api
安裝lumen
composer create-project --prefer-dist laravel/lumen blog
拷貝配置
copy .env.example .env
啟動
php -S localhost:83 -t public
生成APP_KEY
由於lumen
無key:generate
命令,所以需要建立檔案
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputOption;
class KeyGenerateCommand extends Command
{
// 命令名
protected $name = 'key:generate';
// 描述
protected $description = "Set the application key";
// 執行
public function handle() {
$key = $this->getRandomKey();
if ($this->option('show')){
$this->line('<command>'.$key.'</command>');
return;
}
$path = base_path('.env');
if (file_exists($path)){
file_put_contents($path, str_replace('APP_KEY='.env('APP_KEY'), 'APP_KEY='.$key, file_get_contents($path)));
}
$this->info("Application key [$key] set successfully.");
}
/**
* @return string
* 獲取隨機32key
*/
protected function getRandomKey(){
return Str::random(32);
}
protected function getOptions()
{
return [
['show', null, InputOption::VALUE_NONE, 'Simply display the key instead of modifying files.']
];
}
}
新增命令到app/Console/Kernel.php
檔案中
<?php
namespace App\Console;
use App\Console\Commands\KeyGenerateCommand;
use Illuminate\Console\Scheduling\Schedule;
use Laravel\Lumen\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
KeyGenerateCommand::class
];
}
生成key
D:\phpstudy_pro\WWW\lumen>php artisan key:generate
Application key [wRtxrX9DZs8HlZ0WMERxHo43Mkjbev1l] set successfully.
修改配置
APP_NAME=Lumen
APP_ENV=local
APP_KEY=wRtxrX9DZs8HlZ0WMERxHo43Mkjbev1l
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=Asia/Shanghai
LOG_CHANNEL=stack
LOG_SLACK_WEBHOOK_URL=
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=lumen
DB_USERNAME=root
DB_PASSWORD=phpTest1!
CACHE_DRIVER=file
QUEUE_CONNECTION=sync
安裝jwt
composer require tymon/jwt-auth
配置啟動檔案
修改boostrap/app.php
<?php
require_once __DIR__.'/../vendor/autoload.php';
(new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables(
dirname(__DIR__)
))->bootstrap();
date_default_timezone_set(env('APP_TIMEZONE', 'UTC'));
$app = new Laravel\Lumen\Application(
dirname(__DIR__)
);
$app->withFacades();
$app->withEloquent();
$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);
$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);
$app->configure('app');
// 認證中介軟體
$app->routeMiddleware([
'auth' => App\Http\Middleware\Authenticate::class,
]);
// $app->register(App\Providers\AppServiceProvider::class);
$app->register(App\Providers\AuthServiceProvider::class);
// $app->register(App\Providers\EventServiceProvider::class);
// jwt註冊
$app->register(\Tymon\JWTAuth\Providers\LumenServiceProvider::class);
$app->router->group([
'namespace' => 'App\Http\Controllers',
], function ($router) {
require __DIR__.'/../routes/api.php';
require __DIR__.'/../routes/web.php';
});
return $app;
生成祕鑰
php artisan jwt:secret
# 檢視.env
JWT_SECRET=JGPUooBjSd2PI91nizCI10ZfI56yLsl9dg9GiUozf8pgjfOS9fPYeTpgVIJaSbBG
自定義響應格式
載入此檔案,需要在composer.json
新增一下程式碼
"autoload": {
...
"files": [
"app/Helpers/helper.php"
]
},
<?php
/**
* 響應格式
*/
if (!function_exists('resp')) {
function resp($code = 200, $msg = '', $data = []) {
return response()->json([
'code' => $code,
'msg' => $msg,
'data' => $data,
]);
}
}
使用者認證
使用make:migration
生成表
預設此檔案已存在,如果不存在則建立
D:\phpstudy_pro\WWW\lumen>php artisan make:migration create_users_table --create=users
Created Migration: 2020_09_18_103745_create_users_table
定義表欄位
<?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->increments('id');
$table->string('username');
$table->string('password');
$table->string('email');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
資料遷移
D:\phpstudy_pro\WWW\lumen>php artisan migrate
Migrating: 2020_09_18_103745_create_users_table
Migrated: 2020_09_18_103745_create_users_table (280.89ms)
修改User
模型
<?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;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject
{
use Authenticatable, Authorizable, HasFactory;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'username', 'email', 'password'
];
/**
* The attributes excluded from the model's JSON form.
*
* @var array
*/
protected $hidden = [
'password',
];
/**
* @inheritDoc
* 獲取jwt中的使用者標識
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* @inheritDoc
* 獲取jwt中的使用者自定義欄位
*/
public function getJWTCustomClaims()
{
return [];
}
}
配置認證guard
拷貝vendor/laravel/lumen-framework/config/auth.php
到 config/
目錄下,並修改如下:
<?php
return [
'defaults' => [
'guard' => env('AUTH_GUARD', 'api')
],
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users'
]
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \App\Models\User::class
]
],
'passwords' => [
//
],
];
定義路由檔案api.php
<?php
/** @var \Laravel\Lumen\Routing\Router $router */
// 建立使用者和登入
$router->group([
'prefix' => 'auth',
'namespace' => 'Api',
], function () use ($router) {
$router->post('/store', 'UserController@store');
$router->post('/login', 'UserController@login');
$router->get('/user', 'UserController@index');
$router->get('/me', 'UserController@me');
$router->get('/logout', 'UserController@logout');
});
建立UserController
<?php
namespace App\Http\Controllers\Api;
use App\Exceptions\Code;
use App\Exceptions\Msg;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* UserController constructor.
* 認證中介軟體,排除登入和註冊
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login','store']]);
}
/**
* @return \Illuminate\Http\JsonResponse
* 所有使用者
*/
public function index() {
$users = User::paginate(env('PAGINATE'));
return resp(Code::Success, Msg::Success, $users);
}
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* 登入
*/
public function login(Request $request) {
$message = [
'username.required' => "請輸入使用者名稱",
'password.required' => "請輸入密碼",
];
$validator = Validator::make($request->all(), [
'username' => 'required',
'password' => 'required'
], $message);
if ($validator->fails()) {
foreach($validator->errors()->getMessages() as $error) {
return resp(Code::LoginFailed, $error[0]);
}
}
$credentials = request(['username', 'password']);
if (! $token = auth()->attempt($credentials)) {
return resp(Code::LoginFailed, Msg::LoginFailed);
}
return resp(Code::LoginSuccess, Msg::LoginSuccess, $this->responseWithToken($token));
}
/**
* @param $token
* @return array
* 返回token資訊
*/
protected function responseWithToken($token) {
return [
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth()->factory()->getTTL() * env('JWT_TTL')
];
}
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
* 建立使用者
*/
public function store(Request $request)
{
$message = [
'email.required' => '請輸入郵箱',
'email.email' => '郵箱格式不正確',
'email.unique' => '郵箱已存在',
'username.required' => '請輸入使用者名稱',
'password.required' => '請輸入密碼',
'username.min' => '使用者名稱至少 :min 位',
'password.min' => '密碼至少 :min 位',
];
$validator = Validator::make($request->input(), [
'email' => 'required|email|unique:users',
'username' => 'required|min:6',
'password' => 'required|min:8',
], $message);
if ($validator->fails()) {
foreach($validator->errors()->getMessages() as $error) {
return resp(Code::CreateUserFailed, $error[0]);
}
}
$username = $request->get('username');
$email = $request->get('email');
$password = $request->get('password');
$attributes = [
'email' => $email,
'username' => $username,
'password' => app('hash')->make($password)
];
$user = User::create($attributes);
return resp(Code::CreateUserSuccess, Msg::CreateUserSuccess, $user);
}
/**
* @return \Illuminate\Http\JsonResponse
* 當前使用者資訊
*/
public function me() {
return resp(Code::UserIsMe, Msg::UserIsMe, auth()->user());
}
/**
* @return \Illuminate\Http\JsonResponse
* 退出登入
*/
public function logout() {
auth()->logout();
return resp(Code::LoginOutSuccess, Msg::LoginOutSuccess);
}
/**
* @return array
* 重新整理token
*/
public function refresh(){
return $this->responseWithToken(auth()->refresh());
}
}
定義返回狀態碼和資訊
<?php
namespace App\Exceptions;
class Code
{
const Success = 200;
const Unauthorized = 401;
const Failed = 500;
const CreateUserSuccess = 10001;
const CreateUserFailed = 10002;
const LoginSuccess = 20001;
const LoginFailed = 20002;
const LoginOutSuccess = 20003;
const UserIsMe = 20004;
const CreatePostsSuccess = 30001;
const CreatePostsFailed = 30002;
const PostsListSuccess = 30003;
const PostsListFailed = 30004;
}
<?php
namespace App\Exceptions;
class Msg
{
const Success = '成功';
const Unauthorized = '未認證';
const Failed = '失敗';
const CreateUserSuccess = '建立使用者成功';
const CreateUserFailed = '建立使用者失敗';
const LoginSuccess = '登入成功';
const LoginFailed = '登入失敗';
const LoginOutSuccess = '退出成功';
const UserIsMe = '獲取當前使用者';
const CreatePostsSuccess = '建立文章成功';
const CreatePostsFailed = '建立文章失敗';
const PostsListSuccess = '查詢文章列表成功';
const PostsListFailed = '查詢文章列表失敗';
}
測試建立使用者
使用postman
工具
建立使用者
登入使用者
當前使用者
使用者列表
退出登入
本作品採用《CC 協議》,轉載必須註明作者和本文連結