thinkphp5.1-jwt的安裝與使用
安裝jwt插件
“firebase/php-jwt”: “^5.0”
在項目根目錄下執行composer update即可.
立即學習“PHP免費學習筆記(深入)”;
創建一個auth中間件
php think make:middleware Auth
打開applicationhttpmiddlewareAuth文件
<?php namespace apphttpmiddleware; use FirebaseJWTJWT; use FirebaseJWTSignatureInvalidException; use thinkexceptionTokenException; use thinkexceptionValidateException; use think acadeCache; use think acadeConfig; class Auth { public function handle($request, Closure $next) { $bearer_token = []; $bearer = $request->header('authorization');//取header中的token ?if?($bearer?!==?null)?{ ?//不空嘗試去匹配 ?preg_match('/bearers*(S+)/i',?$bearer,?$bearer_token); ?} ?if?(empty($bearer_token[1]))?{ ?//匹配不到結果嘗試去url中獲取 ?if?($request->param('token')?!==?null)?{ ?$token?=?$request->param('token'); ?}else{ ?throw?new?TokenException('請登錄',?401); ?} ?}else{ ?$token=$bearer_token[1]; ?} ?try?{ ?$de_token?=?JWT::decode($token,?Config::get('JWT_KEY'),?Config::get('JWT_ENCRYPTION')); ?}?catch?(SignatureInvalidException?$exception)?{ ?//捕獲JWT解析錯誤 ?throw?new?TokenException('無效令牌',?401); ?}?catch?(Exception?$exception)?{ ?throw?new?TokenException('請重新登錄',?401); ?} ?if?($de_token->voe?exp?>?time())?{ ?throw?new?TokenException('請換取新令牌',?402); ?}?else?if?($de_token->voe?get('token_'?.?$de_token->data->uid)?!=?$token)?{ ?throw?new?TokenException('用戶信息錯誤,請重新登錄',?401); ?} ?if?($de_token->data->is_ban?==?1)?{ ?throw?new?ValidateException('該賬戶已被封禁'); ?} ?$request->auth?=?$de_token->data->uid; ?return?$next($request); ?} }
創建一個控制器Login
php think make:controller login/Login –plain
代碼如下
<?php namespace applogincontroller; use appcommonhelp; use appcommonserviceOperationToken; use thinkController; use thinkDb; use thinkRequest; class Login extends Controller { public function login(Request $request) { $info = Db::name('user')->field('id,uuid,nick,gender,icon,im_accid,im_icon,is_ban')->where('del_time',?'=',?'0')->where(['mobile'?=>?$request->param('phone'),?'password'?=>?md5($request->param('password'))])->findOrEmpty(); ?if?($info?==?null?||?empty($info))?{ ?return?help::errJsonReturn('賬號或密碼錯誤'); ?} ?$token?=?OperationToken::crearToken($info['id'],?$info['uuid'],?$info['is_ban']); ?return?json([ ?'type'?=>?'Bearer?', ?'access_token'=>$token['token'], ?'exp_time'=>$token['exp'], ?'voe_time'=>$token['voe'], ?'iat_time'=>time() ?]); ?} }
在application下新建common文件夾,在common下新建service文件夾,service文件夾下創建
OperationToken.php
<?php namespace appcommonservice; use thinkDb; use think acadeCache; use FirebaseJWTJWT; use think acadeConfig; class OperationToken { public static function crearToken(int $uid, string $uuid, int $is_ban): array { $time = time(); $info_token = [ 'iat' =>?$time,//簽發時間 ?'voe'?=>?Config::get('TOKEN_VOE',7200)?+?$time,//換取有效時間 ?'exp'?=>?Config::get('TOKEN_EXP',3600)+$time,//有效時間 ?'sign'?=>?base64_encode($uuid),//簽名 ?'data'?=>?[ ?'uid'?=>?$uid,//用戶id ?'is_ban'?=>?$is_ban,//是否被禁用 ?] ?]; ?$token?=?JWT::encode($info_token,?Config::get('JWT_KEY')); ?Cache::tag('login')->set('token_'?.?$uid,?$token,?Config::get('TOKEN_VOE',7200)?+?$time); ?Db::name('user_login_log')->insert( ?[ ?'uid'=>$uid, ?'token'=>$token, ?'iat_time'=>$time, ?'ip'=>ip2long(request()->ip()), ?'exp_time'=>Config::get('TOKEN_EXP',3600)+$time, ?'voe_time'=>?Config::get('TOKEN_VOE',7200)?+?$time ?] ?); ?return?[ ?'token'=>$token,? ?'voe'?=>Config::get('TOKEN_VOE',7200)?+?$time, ?'exp'?=>?Config::get('TOKEN_EXP',3600)+$time]; ?} }
?
config/app.php文檔末尾追加參數并接管錯誤控制
//?異常處理handle類?留空使用?thinkexceptionHandle 'exception_handle'?=>?function?($e)?{ ?//參數驗證錯誤 ?if?($e?instanceof?thinkexceptionValidateException)?{ ?return?json(['msg'?=>?$e->getError()],?422); ?} ?//route未定義 ?if?($e?instanceof?thinkexceptionValidateException)?{ ?return?json(['msg'?=>?$e->getMessage()],?404); ?}?//token過期/無效?401-令牌/賬號密碼錯誤?402-令牌過期可舊換新?403-無權限訪問 ?if?($e?instanceof?hinkexceptionTokenException)?{ ?return?json(['msg'?=>?$e->getError()],?$e->getCode()); ?}?//?請求異常 ?if?($e?instanceof?HttpException?&&?request()->isAjax())?{ ?return?response(['msg'?=>?$e->getMessage()],?$e->getStatusCode());? }? },
thinkphp5.1-jwt的安裝與使用與路由參數驗證
在thinkphplibrary?hinkexception下新建TokenException.php
代碼如下
<?php namespace thinkexception; class TokenException extends HttpException { protected $error; public function __construct($error, $code = 0) { $this->error?=?$error; ?$this->message?=?$error; ?$this->code?=?$code; ?} ?/** ?*?獲取驗證錯誤信息 ?*?@access?public ?*?@return?array|string ?*/ ?public?function?getError() ?{ ?return?$this->error; ?} }
創建一個login的驗證器
php think make:validate login/Login
代碼如下
<?php namespace applogin validate;use thinkValidate;class Login extends Validate { /** * 定義驗證規則 * 格式:'字段名' =>?['規則1','規則2'...] ?* ?*?@var?array?*/ ?protected?$rule?=?[?'phone'=>'require|mobile', ?'password'=>'require|length:4,12' ?];? ?/** ?*?定義錯誤信息 ?*?格式:'字段名.規則名'?=>?'錯誤信息' ?* ?*?@var?array?*/ ?protected?$message?=?[?'phone.mobile'=>'phone格式錯誤', ?'password.length'=>'密碼長度錯誤' ?];?protected?$scene=[?'login'=>['phone','password'] ?]; }
打開route/route.php
代碼如下
<?php use think acadeRoute; Route::get('/','index/Index/index'); Route::group('account',function (){ Route::post('/login','login/Login/login')->validate('applogin alidateLogin','login'); }); //需要驗證登錄 Route::group('api',function?(){ ?Route::post('/user','index/Index/index'); })->middleware(apphttpmiddlewareAuth::class);
這里的middleware按照官方文檔是可以注冊到middleware.php中,但在測試中發現問題.路由不執行middleware方法在訪問時會由上至下順序執行middleware.php中注冊的所有中間件,因此改寫為middleware(apphttpmiddlewareAuth::class);去使用中間件在common下新建一個help.php
代碼如下
<?php namespace appcommon; class help { public static function susJsonReturn(array $data=[],string $msg='請求成功',int $code=1) { return json([ 'msg'=>$msg, ?'data'=>$data, ?'code'=>$code ?]); ?} ?public?static?function?errJsonReturn(string?$msg?=?'請求失敗',?int?$code?=?0,?array?$data?=?[]) ?{ ?return?json([ ?'msg'=>$msg, ?'data'=>$data, ?'code'=>$code ?]); ?} }
到數據庫中新建一個數據庫,新建兩張表
CREATE?TABLE?`xn_user`?( ?`id`?int(11)?unsigned?NOT?NULL?AUTO_INCREMENT, ?`uuid`?varchar(32)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'uuid', ?`password`?varchar(32)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'登錄密碼', ?`name`?varchar(20)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'真實姓名', ?`nick`?varchar(8)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'昵稱', ?`gender`?enum('1','2','0')?COLLATE?utf8mb4_unicode_ci?NOT?NULL?DEFAULT?'0'?COMMENT?'用戶性別,0?表示未知,1?表示男,2?女表示女', ?`regist_time`?int(11)?unsigned?DEFAULT?NULL, ?`icon`?varchar(255)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'頭像', ?`mobile`?char(11)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'手機號', ?`im_accid`?varchar(32)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'im賬號', ?`im_icon`?varchar(255)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'im頭像', ?`im_email`?varchar(50)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'im郵箱', ?`im_birth`?varchar(16)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'im生日', ?`im_mobile`?varchar(32)?COLLATE?utf8mb4_unicode_ci?DEFAULT?''?COMMENT?'im手機號碼', ?`create_time`?int(11)?unsigned?DEFAULT?'0', ?`del_time`?int(11)?unsigned?DEFAULT?'0', ?`is_ban`?enum('0','1')?COLLATE?utf8mb4_unicode_ci?DEFAULT?'0'?COMMENT?'是否封號', ?PRIMARY?KEY?(`id`) )?ENGINE=InnoDB?AUTO_INCREMENT=2?DEFAULT?CHARSET=utf8mb4?COLLATE=utf8mb4_unicode_ci; CREATE?TABLE?`xn_user_login_log`?( ?`uid`?int(11)?NOT?NULL?DEFAULT?'0'?COMMENT?'用戶id', ?`token`?text?COLLATE?utf8mb4_unicode_ci?NOT?NULL?COMMENT?'登錄時的令牌', ?`iat_time`?int(11)?DEFAULT?'0'?COMMENT?'登錄時間', ?`ip`?bigint(20)?unsigned?DEFAULT?'0'?COMMENT?'登錄ip-ip2long', ?`exp_time`?int(11)?DEFAULT?'0'?COMMENT?'失效時間', ?`voe_time`?int(11)?DEFAULT?'0'?COMMENT?'token舊換新有效時間', ?KEY?`login_log_uid`?(`uid`,`ip`,`token`(32))?USING?BTREE )?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4?COLLATE=utf8mb4_unicode_ci;
推薦教程:《TP5》