【Uniapp】小程序携带Token请求接口+无感知登录方案2.0

慈云数据 2024-03-19 技术支持 96 0

本次改进原文《【Uniapp】小程序携带Token请求接口+无感知登录方案》,在实际使用过程中我发现以下bug:

  1. 若token恰好在用户访问接口时到期,就会直接查询为空,不反映token过期问题(例如:弹窗显示订单查询记录为空),并不是因为没有数据而是因为token过期了,接口返回了但是没有在前端显示
  2. token过期后需要重新启动小程序,才会获取到新的token
  3. 获取到token后,原接口不会继续请求,页面页面空白没有任何数据,数据需要下一次刷新才有

问题演示如下:

【审核中】

目录

  • 吐槽
    • token 是什么?
    • 设计思路(点击方法可跳转原文档)
    • 操作流程
      • 后端代码
      • 前端小程序封装📦代码
      • 演示
        • 1、不存在本地缓存、不存在redis记录 演示
        • 2、不存在本地缓存演示
        • 3、服务器端不存在redis记录 演示
        • 如何进行token鉴权
        • thinkphp5 redis补充
        • 2.0改进方案
        • 总结

          在这里插入图片描述

          吐槽

          写本篇的原因是因为之前开发用的都不是微信小程序给的session作为token鉴权的,这次开发打算使用多端同步的uniapp开发小程序,方便后面转多端,所以我想尝试新的东西,另外在热榜中我看到一篇文章用"access_token作为token来请求验证接口、checkSession用来检测access_token有无过期",不得不使我感叹,现在的技术er这么差了吗?简直就是误人子弟!!

          我们来说说为什么不能用access_token作为token

          • 【官方回答】access_token 是小程序全局唯一后台接口调用凭据,调用绝大多数后台接口时都需使用。开发者可以通过 getAccessToken 接口获取并进行妥善保存。 -【官方回答】

            获取小程序全局唯一后台接口调用凭据,token有效期为7200s,开发者需要进行妥善保存。

            所以说,access_token 只是用来调用一些微信提供的api服务的,并且access_token 只有两个小时,你把access_token当作小程序的token?不仅不满足暴露这个问题,时间上也有限制

            我们再来说说checkSession是用来检测什么的?

            • 登录态过期后开发者可以再调用 wx.login 获取新的用户登录态。调用成功说明当前 session_key 未过期,调用失败说明 session_key 已过期。

              所以!checkSession是用来检测session_key而不是access_token的,access_token是根据小程序的appid和secret确定的,没有单一用户代表性

              在这里插入图片描述

              token 是什么?

              token 顾名思义就是令牌,也就是一种身份标志。用于和服务器确定身份,它具有时效性,超过有效时间身份标志就会失效。

              在这里插入图片描述

              设计思路(点击方法可跳转原文档)

              通过小程序客户端发起的**wx.login()** 获取临时登录凭证code ,并回传到开发者服务器,通过微信提供的 auth.code2Session 接口,换取 用户唯一标识 openid、 会话密钥 session_key。并通过以session_key为名,openid为值将数据存放到redis中,在这里我将时间设置为48h

              1. 若服务端token失效,客户端登陆状态也会失效,失效后重新登陆执行上述步骤;
              2. 若客户端checkSession失效或者本地数据缓存失效,则也会重新登录

                上述两个步骤保证小程序端的token都是最新的,缺点是不能及时性作废原先在服务器存储的数据只能等redis过期

              以上设计逻辑思路满足下图:

              在这里插入图片描述

              操作流程

              后端代码

              以Thinkphp5.0.24为案例(20230614新增控制器写法,原来写的是原生php,二选一,建议第一种)

              1.TP控制器登录接口方法(建议)

                 //登录接口
                  //  http://code.taila.club/index.php/index/api/login
                  // 目录\控制器\方法
                  public function login()
                  { 
                      $code=input('code');
                      if ($code) {
                          // 存在记录
                          // $res=Db::table("sys")->where("id","1")->find();
                          
                          // $appid=$res["val1"];//小程序id
                          // $secret=$res["val2"];//密钥
                          $appid="w***********e";
                          $secret="6***************6";
                          $code=$_GET['code'];
                          $url="https://api.weixin.qq.com/sns/jscode2session?appid=$appid&secret=$secret&js_code=$code&grant_type=authorization_code";
                           $header = array(
                     'Accept: application/json',
                  );
                  $curl = curl_init();
                  //设置抓取的url
                  curl_setopt($curl, CURLOPT_URL, $url);
                  //设置头文件的信息作为数据流输出
                  curl_setopt($curl, CURLOPT_HEADER, 0);
                  // 超时设置,以秒为单位
                  curl_setopt($curl, CURLOPT_TIMEOUT, 1);
               
                  // 超时设置,以毫秒为单位
                  // curl_setopt($curl, CURLOPT_TIMEOUT_MS, 500);
               
                  // 设置请求头
                  curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
                  //设置获取的信息以文件流的形式返回,而不是直接输出。
                  curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
                  curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
                  curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
                  //执行命令
                  $data = curl_exec($curl);
               
                  // 显示错误信息
                  if (curl_error($curl)) {
                      print "Error: " . curl_error($curl);
                        die(
                      json_encode(
                          array(
                          'code' => 100,
                          'data' => '',
                          'msg' => '请求出错!'
                      ),480));
                  } else {
                      // 打印返回的内容
                      $result=json_decode($data,true);
                      if (array_key_exists("errcode",$result))
                        {
                      //   echo "键存在!";
                     
                       die(
                      json_encode(
                          array(
                          'code' => 100,
                          'data' => '',
                          'msg' => '获取token失败!'.$result['errmsg']
                      ),480));
                      
                        }
                      else
                        {
                      //   echo "键不存在!";
                            // 开启redius
                     
                       //写入redius session_key名命的openid数据 默认存储2天
                      curl_close($curl);
                      $Redis=new Redis();
                      $Redis->set($result['session_key'],$result['openid'],24*60*60*2);
                       die(
                      json_encode(
                          array(
                          'code' => 200,
                          'data' => $result,
                          'msg' => '获取token成功'
                      ),480));
                        }
                       
                      
                     
                     
                        
                  }
                        
                      } else {
                          // 已被处理或者不存在 请求重新登陆
                          die(
                      json_encode(
                          array(
                          'code' => 100,
                          'data' => '',
                          'msg' => '非法操作'
                      ),480)
              );
                      }
                      
                  
                     
                  } 
              
              1. 在public文件夹创建php文件access_token.php(不建议)

                用于接收前端wx.login方法获得的code换回openid和session_key,并通过以session_key为名,openid为值将数据存放到redis中,在这里我将时间设置为48h

               
              
              1. 在tp框架中(application/index/controller)新建Api.php控制器

                用来检测服务器端的token是否存在,以便于让小程序做出重新登录操作

微信扫一扫加客服

微信扫一扫加客服

点击启动AI问答
Draggable Icon