🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由、模型与数据库操作 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.跨域且传输数据,并优化后端接口 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录(一),密码的bcrypt(hash)加密与验证 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口 > 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片 ###### 1.生成token (1)安装jwt包 使用composer方法: ~~~ composer require firebase/php-jwt ~~~ ![](https://img.kancloud.cn/cb/19/cb194af110651e70578cd091e71a2dd8_1459x1073.png) (2)编写生成token方法 ~~~ function setToken($password) { $key = "aslfjhasgjgja"; $token=array( "iss"=>$key, //签发者 可以为空 "aud"=>'', //面象的用户,可以为空 "iat"=>time(), //签发时间 "nbf"=>time(), //在什么时候jwt开始生效 (这里表示签发后立即生效) "exp"=> time()+1*60*60*48, //token 过期时间1秒*60*60*48=两天 "data"=>[ //加入password,后期同样使用password进行比对 'password'=>$password, ] ); $jwt = JWT::encode($token, $key, "HS256"); //根据参数生成了 token return $jwt; } ~~~ ![](https://img.kancloud.cn/58/a6/58a684c26a45721bc68ed050366ce6a6_693x522.png) 下方调用生成token的方法: ![](https://img.kancloud.cn/96/05/9605f6d7b2e231346b9d076bd46eb9bb_709x519.png) 测试: ![](https://img.kancloud.cn/aa/b6/aab63a52cc98be322a4664087cb06653_1215x469.png) 登录生成token值: ![](https://img.kancloud.cn/af/a5/afa50ee4f2dd64a285a8aa6ec8f3af1a_1215x766.png) ###### 2.验证登陆状态 (1)将token值存入本地缓存(上篇login模板已经写好): ![](https://img.kancloud.cn/da/38/da386d3d906895e30b34091aeb994ff6_858x594.png) 检查本地缓存: ![](https://img.kancloud.cn/62/86/62865e79f6a376c625428dc86d9a0c06_1205x168.png) 没问题。 (2)验证token: 我们需要将token值存入发送请求的请求头中,做到只要调用接口,就可以将token一并发送到后端,从而对token登陆状态进行比对验证。 第一步,前端admin端通过请求头将token传值给后端: 在http.js中全局设置获取token,将token值传入请求头Request Headers中,然后后台接口中直接从请求头中获取token,从而实现验证。 这里使用axios里的Interceptors方法,详细可查阅axios手册: ![](https://img.kancloud.cn/18/24/1824f16b32c27ae4ce1fe93b279a018b_1543x1142.png) admin/http.js前端admin端将token传入请求头Request Header: ~~~ // 使用axios的interceptors拦截器,将http调用时拦截 http.interceptors.request.use(function(config){ // 将token值传入请求头,"bearer + 空格"是代码规范,看到Bearer(持票人)大家就明白是对token的验证 config.headers.Authorization = 'bearer ' + localStorage.token return config }, function(error){ // 错误处理 return Promise.reject(error) }) ~~~ ![](https://img.kancloud.cn/c7/c4/c7c42244d29a1b083103155a6e35490d_1326x672.png) ![](https://img.kancloud.cn/94/e7/94e7d9e14116aa8f46ccdf7dbf48d8af_1215x916.png) 随便调用一个接口测试: 第二步,后端获取请求头中的token值,并解析token 因为所有接口的调用都需要验证token,所以我们学习tp6的中间件,在每次接口调用时都使用此中间件进行token验证。 middleware/compareToken.php: ~~~ <?php namespace app\admin\middleware; use \Firebase\JWT\JWT; class compareToken{ public function handle ($request, \Closure $next){ // 获取请求头header中的authorization(token值) $token = request() -> header('authorization'); // 去除token值中的bearer+空格标识 $token = str_replace('bearer ', '', $token); // return response($token); if($token === "undefined"){ // abort终止操作,返回结果 abort(json(['message' => '登陆状态失效,请重新登录', 'code' => 401], $httpCode = 401)); // return response($code); } // key必须与生成token值得字符串相同 $key='aslfjhasgjgja'; try { JWT::$leeway = 60;//当前时间减去60,把时间留点余地用于后面的操作 $decoded = JWT::decode($token, $key, array('HS256')); //HS256方式,这里要和签发的时候对应 // 解析过程中如果出现不对的情况就利用下方catch方法,利用jwt解析问题返回错误信息 } catch(\Firebase\JWT\SignatureInvalidException $e) { // token不正确 abort(json(['message' => '登陆状态失效,请重新登录', 'code' => 401], $httpCode = 401)); } catch(\Firebase\JWT\BeforeValidException $e) { // token过了之前设置的两天期限 abort(json(['message' => '登陆状态失效,请重新登录', 'code' => 401], $httpCode = 401)); } catch(\Firebase\JWT\ExpiredException $e) { // token过期 abort(json(['message' => '登陆状态失效,请重新登录', 'code' => 401], $httpCode = 401)); } catch(Exception $e) { //其他错误 abort(json(['message' => '登陆状态失效,请重新登录', 'code' => 401], $httpCode = 401)); } // 如果没问题,就执行下一步接口函数操作 return $next($request); } } ~~~ ![](https://img.kancloud.cn/17/cd/17cd2f805ad4893f0175784953ccbcd0_1459x1073.png) admin/middleware.php: ~~~ <?php // 这是系统自动生成的middleware定义文件 return [ // token验证 app\admin\middleware\compareToken::class ]; ~~~ ![](https://img.kancloud.cn/85/b6/85b6c37ed9104fb16247fdd60e1a239a_1248x742.png) 测试,刷新页面: ![](https://img.kancloud.cn/8c/ea/8cead14d927a01fc8ad53c4b4e76b3c2_1215x860.png) 没问题,是因为之前我们登录时有token,下一步将localstorage中的token删除: ![](https://img.kancloud.cn/98/0d/980dd4202fe9b9a1ef3683df5fbfd824_276x178.png) 再次刷新页面测试: ![](https://img.kancloud.cn/a5/10/a51084c0027eb5ff82facfcae45966ab_1215x860.png) 到此token验证成功。 但是还有一个问题,我们无法进行登录,因为登录接口同样使用了token验证中间件。 第三步,路由分组,使用路由中间件 (1)使用路由分组 ![](https://img.kancloud.cn/c9/08/c9085d61d5c7807ffdd803ebd5955eb7_882x561.png) (2)使用路由中间件 注释掉全局路由: ![](https://img.kancloud.cn/ba/75/ba757868f11ea5b1d2b11871e5a18305_929x192.png) 使用路由中间件,作用于数据库接口路由组: ![](https://img.kancloud.cn/16/db/16dbb402e20ceec58b87e92c4ec1b46c_710x468.png) 登录测试,成功登录: ![](https://img.kancloud.cn/80/55/8055e62fd410f995a67f446c23a4e8db_1215x414.png) 删除localstorage,刷新测试,正确跳转登录: ![](https://img.kancloud.cn/0f/8b/0f8b67b4cce0d082db5da890526d066d_1215x414.png) 但是经过多次测试后,发现会报错,说是跨域问题: ![](https://img.kancloud.cn/45/da/45daeb918419869e8cbc46a5deddc4f0_1215x860.png) 但是经过一整天的排查,跟跨域一点关系都没有。是请求request的问题。 说白了就是中间件next()之后request接受不到数据,于是我把return next()放在了函数首部: ![](https://img.kancloud.cn/75/32/7532cd42f1db7fd21f3f702456e7d270_1459x1073.png) 至此之后不回出现跨域错误问题。 注意:他娘的tp6框架当你使用了框架内置的跨域之后就不要怀疑跨域会出问题,所有request请求相关问题他都会报错说Cor error,大家不要在跨域上浪费时间!!!我白白浪费一天。 到此后端token验证成功。 但是有些页面没有使用到后端接口,所以不会跳转登陆页面: ![](https://img.kancloud.cn/83/4a/834ae6a17c64fddb18550fbbbf8ff48c_768x459.png) 所以前端页面我们需要用到vue的导航守卫。 ###### 3.导航守卫 此时我们只要调用接口就会解析token,但是进入没有接口的页面就不会跳转。如果我们不想让用户在不登陆的状态下访问我们的所有网页,就需要在前端也设置token判断,做到只要不登录,就无法访问所有页面。 这里我们就需要用到Vue的导航守卫。 大家可以查看我之前的文章进行设置,纯前端操作,不涉及后端: > 技能学习:学习使用Node.js + Vue.js,开发前端全栈网站-12-4.登陆的前端vue-router路由验证(导航守卫) 再注意:node.js + vue.js此篇文章使用的是sessionStorage,本篇文章我们使用的是localStorage,大家最终函数处应改为localStorage,否则无法登录。 ![](https://img.kancloud.cn/a9/a4/a9a4324256507dc1ae2bea76aca54d96_508x268.png) 此时登录功能全部完成,下篇文章我们做分类功能,同时学习通用CRUD接口,让分类功能与管理员功能使用同一组接口函数。