thinkphp6: 前后端分离:用jwt+middleware做用户登录验证(php 8.1.1 / thinkphp v6.0.10LTS )
一,安装firebase/php-jwt扩展:
1,命令:liuhongdi@lhdpc:/data/php/admapi$ composer require firebase/php-jwt2,安装成功后的位置:

liuhongdi@lhdpc:/data/php/admapi$ composer show firebase/php-jwt

说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest
对应的源码可以访问这里获取: https://github.com/liuhongdi/
或: https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,前端vue代码:
Login.vue
<template> <div style="padding:20px;display: flex;align-items:center;justify-content: center;"> <form :model="account" style="margin-top:50px;width:400px;"> <input v-model="account.username" placeholder="请输入用户名" style="width:392px;font-size:16px;" /><br/> <input v-model="account.password" type="password" placeholder="请输入密码" style="width:392px;margin-top:10px;font-size:16px;" /><br/> <div @click="login" style="margin-top:10px;width: 100%;height:40px;line-height:40px;background: #ff0000;border-radius: 10px;"> 登录 div> <div @click="info" style="margin-top:10px;width: 100%;height:40px;line-height:40px;background: #ff0000;border-radius: 10px;"> info div> <div class="text-align-right"> div> form> div> template> <script> import { ref, reactive } from "vue"; import { ElMessage } from "element-plus"; import { apiLogin,apiInfo,apiToken} from '@/api/api'; export default { name: "Login", setup() { const accountRef = ref(null); //表单字段 const account = reactive({ username: "", password: "", }); //登录 const login = async () => { console.log('begin login'); var data = new FormData(); data.append("username",account.username); data.append("password",account.password); apiLogin(data).then(res => { //成功 if (res.code == 0) { //保存jwt token到本地 localStorage.setItem('token', res.data.token); //提示 ElMessage.success("登录成功!"); } else { ElMessage.error("登录失败:"+res.msg); } }).catch((error) => { console.log(error) }) }; const login2 = () => { console.log('begin login2'); } const info = () => { apiInfo().then(res => { //成功 if (res.code == 0) { //保存jwt token到本地 //localStorage.setItem('token', res.data.token); //提示 //ElMessage.success("登录成功!"); console.log(res.data); } else { ElMessage.error("用户信息获取失败:"+res.msg); } }).catch((error) => { console.log(error) }) } return { account, //loginRules, accountRef, login, login2, info, //isLoading, }; }, } script> <style scoped> style>
三,后端php代码:
1,创建middlewareliuhongdi@lhdpc:/data/php/admapi$ php think make:middleware CheckJwt Middleware:app\middleware\CheckJwt created successfully.2,CheckJwt的代码:
<?php declare (strict_types = 1); namespace app\middleware; use app\lib\util\JwtUtil; class CheckJwt { /** * 处理请求,得到用户信息 * * @param \think\Request $request * @param \Closure $next * @return Response */ public function handle($request, \Closure $next) { $auth = $request->header('authorization'); if ($auth == null) { return $next($request); } $token = str_replace("Bearer ","",$auth); $jUtil = new JwtUtil(); $res = $jUtil->verifyjwt($token); if (isset($res['code']) && isset($res['userId']) && $res['code'] == 0 && is_int($res['userId'])) { $userId = $res['userId']; $request->auth = $userId; } else { $request->auth = 0; } return $next($request); } }
3,app/middleware.php
使从jwt得到用户信息的middleware生效:
<?php // 全局中间件定义文件 return [ app\middleware\CheckJwt::class, ];
4,controller/Auth.php
<?php declare (strict_types = 1); namespace app\controller; use app\BaseController; use think\facade\Cache; use think\Request; use app\result\Result; use think\response\Json; use app\validate\Login as LoginValidate; use app\validate\GoodsList as GoodsListValidate; use think\exception\ValidateException; use app\lib\util\JwtUtil; class Auth extends BaseController { /** * 登录 * * @return \think\Response */ public function login():Json { try { validate(LoginValidate::class) //->scene('edit') ->check($_POST); } catch (ValidateException $e) { // 验证失败 输出错误信息 return Result::Error(422,$e->getError()); } if ($_POST["username"] == "dddddd" && $_POST["password"] == "111111"){ //验证成功,生成jwt返回 $userId = 123; $jUtil = new JwtUtil(); $token = $jUtil->createJwt($userId); $res = ["token"=>$token]; // 防止重复提交 Cache::delete($key); return Result::Success($res); } else { return Result::Error(422,"用户名密码错误"); } } /** * 得到用户信息 * * @return \think\Response */ public function info() { if ($this->request->auth > 0) { $status = "已登录"; } else { $status = "未登录"; } $info = [ 'userId'=>$this->request->auth, 'status'=>$status, ]; return Result::Success($info); } }
5,lib/util/JwtUtil.php
<?php namespace app\lib\util; use Firebase\JWT\ExpiredException; use Firebase\JWT\JWT; class JwtUtil { private $signKey = "lhd@2001:liuhongdi"; private $timeMinutes = 5; /** * 根据json web token设置的规则生成token * @return \think\response\Json */ public function createJwt($userId):string { $key = md5($this->signKey); //jwt的签发**,验证token的时候需要用到 $time = time(); //签发时间 $expire = $time + $this->timeMinutes*60; //过期时间 $token = array( "userId" => $userId, "iss" => "http://www.liuhongdi.com/",//签发组织 "aud" => "lhd", //签发作者 "iat" => $time, //签发时间 "nbf" => $time, //生效时间 "exp" => $expire //过期时间 ); $jwt = JWT::encode($token,$key); return $jwt; } /** * 验证token * @return \think\response\Json */ public function verifyjwt($token) { $key = md5($this->signKey); //jwt的签发**,验证token的时候需要用到 try{ $jwtAuth = json_encode(JWT::decode($token,$key,array("HS256"))); $authInfo = json_decode($jwtAuth,true); if (!$authInfo['userId']){ return ['code'=>0,'msg'=>"用户不存在"]; } return ['code'=>0,'userId'=>$authInfo['userId'],'msg'=>"ok"]; }catch (ExpiredException $e){ return ['code'=>0,'msg'=>"token过期"]; }catch (\Exception $e){ return ['code'=>0,'msg'=>$e->getMessage()]; } } }
四,效果测试
1,界面:用户名 dddddd,密码;111111,可见php的代码:
2,未登录时点info
3,登录后的返回:


五,查看php和thinkphp的版本:
php:liuhongdi@lhdpc:/data/php/admapi$ php --version PHP 8.1.1 (cli) (built: Dec 20 2021 16:12:16) (NTS) Copyright (c) The PHP Group Zend Engine v4.1.1, Copyright (c) Zend Technologies with Zend OPcache v8.1.1, Copyright (c), by Zend Technologiesthinkphp:
liuhongdi@lhdpc:/var/www/html$ cd /data/php/admapi/ liuhongdi@lhdpc:/data/php/admapi$ php think version v6.0.10LTS