[Uniapp] Small program carrying Token request interface + non-aware login scheme

insert image description here

Make complaints

The reason for writing this article is because the previous development did not use the session given by the WeChat applet as token authentication. This time, I plan to use the multi-terminal synchronized uniapp to develop the applet, which is convenient for later transfer to multiple terminals, so I want to try something new. In addition, in the hot list, I saw an article using " access_tokenas a token to request the verification interface, checkSession is used to detect whether the access_token has expired", I have to sigh, is the current technology er so bad? It's simply a mistake! !

Let's talk about why you can't use access_token as token

  • [Official answer] access_token is the only global background interface calling credential of the Mini Program, and it is required when calling most background interfaces. Developers can get it through the getAccessToken interface and save it properly. - [Official Answer]
    To obtain the globally unique background interface call credentials of the Mini Program, the token is valid for 7200s, and the developer needs to keep it properly.

So, the access_token is only used to call some api services provided by WeChat, and the access_token is only for two hours. Do you use the access_token as the token of the applet? Not only does it not meet the problem of exposure, but there is also a time limit

Let's talk about what checkSession is used to detect?

  • After the login status expires, the developer can call wx.login to obtain a new user login status. A successful call indicates that the current session_key has not expired, and a failed call indicates that the session_key has expired.

so! checkSession is used to detect session_key instead of access_token, access_token is determined based on the appid and secret of the applet, there is no single user representative

insert image description here

What are tokens?

As the name suggests, token is a token, which is a kind of identity mark. It is used to determine the identity with the server. It is time-sensitive, and the identity mark will become invalid after the valid time.
insert image description here

Design ideas (click on the method to jump to the original document)

Get the temporary login credential code through ** wx.login() ** initiated by the applet client , and send it back to the developer server. Through the auth.code2Session interface provided by WeChat , exchange for the user's unique identifier openid and session key session_key. And store the data in redis by using session_key as the name and openid as the value, here I set the time to 48h

  1. If the server token fails, the login status of the client will also fail, and after the failure, log in again and perform the above steps;
  2. If the client checkSession fails or the local data cache fails, it will also log in again
    上述两个步骤保证小程序端的token都是最新的,缺点是不能及时性作废原先在服务器存储的数据只能等redis过期

The above design logic meets the following diagram:
insert image description here

code manipulation

operate

Take Thinkphp5.0.24 as a case

  1. Create a php file access_token.php in the public folder
    用于接收前端wx.login方法获得的code换回openid和session_key,并通过以session_key为名,openid为值将数据存放到redis中,在这里我将时间设置为48h
<?php
//小程序登录
$appid="";//小程序id
$secret="";//密钥
$code=$_GET['code'];
curl_get("https://api.weixin.qq.com/sns/jscode2session?appid=$appid&secret=$secret&js_code=$code&grant_type=authorization_code");
function curl_get($url){
    
    
 
   $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,
            'msg' => '请求出错!'
        ),480));
    } else {
    
    
        // 打印返回的内容
        $result=json_decode($data,true);
        if (array_key_exists("errcode",$result))
          {
    
    
        //   echo "键存在!";
        if ($result['errcode']==0) {
    
    
            // code...
               // 开启redius
         ini_set('session.save_handler', 'redis');
         ini_set('session.save_path', 'tcp://127.0.0.1:6379');
         $redis = new redis();
         $redis->connect('127.0.0.1', 6379);
         //写入redius session_key名命的openid数据 默认存储2天
        curl_close($curl);
        $redis->set($result['session_key'],$result['openid'],24*60*60*2);
        die(
        json_encode(
            array(
            'code' => 200,
            'msg' => $result
        ),480)
);

        } else {
    
    
            die(
        json_encode(
            array(
            'code' => 100,
            'msg' => '获取token失败!'.$result['errmsg']
        ),480));
        }
        
          }
        else
          {
    
    
        //   echo "键不存在!";
         die(
        json_encode(
            array(
            'code' => 100,
            'msg' => '获取token失败'
        ),480));
          }
         
        

       
       
          
    }
}
 ?>
  1. Create a new Api.php controller in the tp framework (application/index/controller)
    用来检测服务器端的token是否存在,以便于让小程序做出重新登录操作
<?php
namespace app\index\controller;
use think\Db;
use think\cache\driver\Redis;
use app\index\controller\Base;
class Api extends Base
{
    
    
    
    // 验证session_key是否过期(服务器默认48h,到期后自动删除,查询不到表示过期)
    public function check_session()
    {
    
     
        $session_key=input('session_key');
        $redis = new Redis();
        //读取数据
        $result= $redis->get($session_key);
        if ($result) {
    
    
            // 存在记录
           die(
        json_encode(
            array(
            'code' => 200,
            'msg' => 'token验证通过'
        ),480)
);
        } else {
    
    
            // 已被处理或者不存在 请求重新登陆
            die(
        json_encode(
            array(
            'code' => 100,
            'msg' => 'token验证失败,请重新登录'
        ),480)
);
        }
        
    
       
    }
}

  1. client wrapper
  • Create a new token.js file code in the project insert image description here
    :
/**
 * token.js,全局校验方法,可以自己补充
 */
export default {
    
    
	login: function(session) {
    
      
		let that = this;
		uni.showLoading({
    
    
		  title: '登录中...'
		});
				
		uni.login({
    
    
		  provider: 'weixin',
		  success: loginRes => {
    
    
		    console.log(loginRes);
		    that.code = loginRes.code;
		    //  将用户登录code传递到后台置换用户SessionKey、OpenId等信息
			uni.request({
    
    
			    url: 'https://serverhost/wx_token.php', //仅为示例,并非真实接口地址。
			    data: {
    
    
			        code:loginRes.code
			    },
				method: 'GET',
			    header: {
    
    
			        'content-type': 'application/x-www-form-urlencoded' //自定义请求头信息
			    },
			    success: (res) => {
    
    
			        console.log(res.data);
			       console.log(res.data.msg.session_key)
				   uni.hideLoading()
				   //存取session
				   uni.setStorageSync('session', res.data.msg.session_key);
				   //openid只需要服务通过session请求redis即可
			    }
			});
		
		   
		  },
		  fail: () => {
    
    
		    uni.showToast({
    
     title: '获取 code 失败', icon: 'none' });
		  }
		});
		
	},
        //检测token 每次发起业务请求检测即可
	check_token: function(session) {
    
      
		let that=this;
		//微信检测
		uni.checkSession({
    
    
		  success () {
    
    
		    //session_key 未过期,并且在本生命周期一直有效
			 console.log("未过期")
			
			 //没有过期在判断下存储是否存在 后需提交业务需要用到
			 const session = uni.getStorageSync('session');
			 	if (session=='') {
    
    
					console.log("session不存在");
					that.login()
			 	}else{
    
    
					//检测服务器的
					console.log("session存在-校验合法性");
					//验证检测服务器session有效性
					uni.request({
    
    
					    url: 'https://serverhost/index.php/index/Api/check_session', //仅为示例,并非真实接口地址。
					    data: {
    
    
					        session_key:session
					    },
						method: 'POST',
					    header: {
    
    
					        'content-type': 'application/x-www-form-urlencoded' //自定义请求头信息
					    },
					    success: (res) => {
    
    
							if (res.data.code!=200)
							{
    
    	
								
								//服务器token已过期 重新登录
								console.log("服务器token已过期 重新登录");
								that.login()
								
							}else{
    
    
								console.log("服务器token有效");
							}
						 
					    }
					});
					
					
					
				}
				
			 
		  },
		  fail () {
    
    
		    // session_key 已经失效,需要重新执行登录流程
		   console.log("session过期")
		   
		   that.login()
		  }
		})
		
		
	
		
	}
}
  • Referenced in main.js, mounted globally
import token from '@/sdk/token.js'

// 挂载到全局
Vue.prototype.$token = token
  • Instructions
 this.$token.check_token()

demo

After uniapp is packaged into a WeChat applet and run

1. There is no local cache, no redis record demo

  • The front-end operation generates a new token, which is recorded in the local cache
    -insert image description here

  • And after the front end logs in, there is a new record in redis
    -insert image description here

2. There is no local cache demo

  • The front end cleared the last token, and after refreshing, it will log in without feeling to get the latest token and record it in the local cache and redis

insert image description here

  • There is a new token record in the backend redis, and the first token becomes invalid after the time countdown ends
    insert image description here

3. There is no redis record demonstration on the server side

  • Delete the token record for the second time, refresh the front-end simulator (do not clear the token), and see the result
    insert image description here

  • After refreshing, the front end cannot detect the token record and perform a re-login to obtain the latest token
    insert image description here

The above has done an experiment on all possibilities, except for the problem of [the last token cannot be invalidated in time after updating the new token], I can't find any other problems

How to perform token authentication

  • Every time the front-end applet initiates a business request, it first calls the encapsulated [check_token] to check whether the local incorrectly stored token, whether the token has expired (determined by WeChat), and whether redis exists on the server side (if it does not exist, there is no need to initiate it, because will still be rejected)

  • To verify whether the token is valid on the server side, you only need to query the token. If it exists, it means success. Take out the openid directly and write the business logic code. If it fails, let the applet log in again. These can be done according to the return code.

Let's watch the demo

  • New controller Index.php (path application/index/controller)

To verify whether the token is valid on the server side, you only need to query the token. If it exists, it means success. Take out the openid directly and write the business logic code. If it fails, let the applet log in again. These can be done according to the return code.

<?php
// 访问路由 https://***/index.php/index/Api/index
namespace app\index\controller;
use think\Db;
use think\cache\driver\Redis;
use app\index\controller\Base;
class Index extends Base
{
    
    
    public function index()
    {
    
     
        // 实例 获取openid
        $token=input('token');
        $redis = new Redis();
        $result= $redis->get($token);
       if ($result) {
    
    
           die(
        json_encode(
            array(
            'code' => 200,
             'data'=>$result,
            'msg' => '数据请求成功'
        ),480)
);
       } else {
    
    
           die(
        json_encode(
            array(
            'code' => 100,
            'data'=>'',
            'msg' => 'token失效或不存在!请重新获取'
        ),480)
);
       }
       
      
    
       
    }
}

make the right request

insert image description here
If a 1 is added after
insert image description here

thinkphp5 redis supplement

$redis->set('name','value','3600');//添加记录前两个分别表示名和值,后者单位秒
$redis->get($session_key);//根据名查询值

Summarize

The above is today’s unaware login solution for uniapp combined with the WeChat applet carrying Token request interface, if you like it, please bookmark it!

Guess you like

Origin blog.csdn.net/qq_35230125/article/details/128917956