欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )

程序员文章站 2024-01-08 14:31:52
...
curl等公共函数方法在文章的最后
Wxbizdatacrypt.php 
/**
 * 对微信小程序用户加密数据的解密示例代码.
 *
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */

namespace app\api\controller;
use app\api\controller\Base;
use think\Model;
use think\Db;
use think\Cache;

include_once	"ErrorCode.php";

class Wxbizdatacrypt
{
    private $appid;
	private $sessionKey;

	/**
	 * 构造函数
	 * @param $sessionKey string 用户在小程序登录后获取的会话**
	 * @param $appid string 小程序的appid
	 */
	public function __construct( $appid, $sessionKey)
	{
		$this->sessionKey = $sessionKey;
		$this->appid = $appid;
	}


	/**
	 * 检验数据的真实性,并且获取解密后的明文.
	 * @param $encryptedData string 加密的用户数据
	 * @param $iv string 与用户数据一同返回的初始向量
	 * @param $data string 解密后的原文
     *
	 * @return int 成功0,失败返回对应的错误码
	 */
	public function decryptData( $encryptedData, $iv, &$data )
	{
		if (strlen($this->sessionKey) != 24) {
			return ErrorCode::$IllegalAesKey;
		}
		$aesKey=base64_decode($this->sessionKey);

        
		if (strlen($iv) != 24) {
			return ErrorCode::$IllegalIv;
		}
		$aesIV=base64_decode($iv);

		$aesCipher=base64_decode($encryptedData);

		$result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

		$dataObj=json_decode( $result );
		if( $dataObj  == NULL )
		{
			return ErrorCode::$IllegalBuffer;
		}
		if( $dataObj->watermark->appid != $this->appid )
		{
			return ErrorCode::$IllegalBuffer;
		}
		$data = $result;
		return ErrorCode::$OK;
	}

}

ErrorCode.php
<?php
namespace app\api\controller;
use app\api\controller\Base;
use think\Model;
use think\Db;
use think\Cache;
/**
 * error code 说明.
 * <ul>

 *    <li>-41001: encodingAesKey 非法</li>
 *    <li>-41003: aes 解密失败</li>
 *    <li>-41004: 解密后得到的buffer非法</li>
 *    <li>-41005: base64加密失败</li>
 *    <li>-41016: base64解密失败</li>
 * </ul>
 */
class ErrorCode
{
	public static $OK = 0;
	public static $IllegalAesKey = -41001;
	public static $IllegalIv = -41002;
	public static $IllegalBuffer = -41003;
	public static $DecodeBase64Error = -41004;
}

?>


本来以为php7.0 mcrypt禁用后 解码会有问题 后来发现官直接用官网给的demo 没发现有啥问题  

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )

下面这个图是获取token  

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )

下面是请求代码里小程序login返回的结果 第一个图为携带参数 这些参数在调用小程序 getuserinfo 里可以得到

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )


第二个图为返回结果 里面结果是自定义的 为了返回给前端用

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )


tp5的一段代码写的比较烂 返回值很随意  微信小程序登录代码如下 后端php代码如下

<?php

namespace app\api\controller;
use app\api\controller\Base;
use think\Model;
use think\Db;
use think\Cache;
//这个不需要继承
class Login  
{

    protected $code;
    protected $wxLoginUrl;
    protected $wxAppID;
    protected $wxAppSecret;
    protected $salt;
    public function __construct()
    {
  
        $this->wxAppID = config('app_id');
        $this->wxAppSecret = config('app_secret');
    }

    //生成token
    public function getcode()
    {

        $code = input("post.code");
        if(!$code)
        {
           
            $data['status'] = 0;
            $data['token'] = '';
            $data['code'] = 0;
            echo json_encode($data);exit;   
        }
        else{

            $this->code = $code;

            $this->wxLoginUrl = sprintf(config('login_url'), 
                $this->wxAppID, 
                $this->wxAppSecret,
                $this->code
            );
            //echo $this->wxLoginUrl;exit;
            $this->salt=config('salt');
        }


        $result = curl_get($this->wxLoginUrl);
   
        $res = json_decode($result,true);

        $data = array();
        if(array_key_exists('errcode', $res))
        {   
            $data['status'] = 0;
            $data['token'] = '';
            $data['code'] = 0;
            echo json_encode($data);exit;   
        }
        else
        {
            $data['status']=1;

            //生成token  
            $token = md5( md5(time().$res['openid']).$this->salt);

            Cache::set($token,1,3600); 
            $cache_data_key = $token."_info";
            Cache::set($cache_data_key,$res,3600);

            $data['token']= $token;

            echo json_encode($data);exit;    

        }
          
        
    }

    //登录 
    public function login()
    {

        $log_path = date("Y/m/d",time());
        $d_path = dirname(dirname(dirname(APP_PATH)))."/xxxx/log/{$log_path}";
        $dir_path = str_replace('\\','/',$d_path);

        if(!is_dir($dir_path))
        {   
            mkdir($dir_path,0777,true);
        }


        $token = input("post.token");
        $cache_data_key = $token."_info";
        $cache_data = Cache::get($cache_data_key);

        if(empty($cache_data))
        {
            $data['status'] = 0;
            $data['data'] = '';
            echo json_encode($data);exit;  
        }

        $encryptedData = input("post.encryptedData");
        $iv = input("post.iv");
        $rawData = input("post.rawData");
        $signature = input("post.signature");

        //先判断信息是否正确
        //signature String  使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息,参考文档 signature。
        $check_signature = sha1($rawData.$cache_data['session_key']);

        if($check_signature!=$signature)
        {
            $data['status']=0;
            $data['data']='';
            echo json_encode($data);exit;  
        }


        $pc = new Wxbizdatacrypt( $this->wxAppID ,$cache_data['session_key'] );
        $errCode = $pc->decryptData($encryptedData, $iv, $wx_data );


        if ($errCode == 0) {
            //解密成功
            $datas=json_decode($wx_data,true);

            if((array_key_exists('head_url', $cache_data)) && (array_key_exists('nickname', $cache_data)))
            {
                    if(($cache_data['head_url']!='')&&($cache_data['nickname']!=''))
                    {
                        if(($datas['head_url']!=$cache_data['head_url'])||($datas['nickname']!=$cache_data['nickname']))
                        {
                            //修改数据库和缓存的头像和昵称
                            
                            $user_save['head_url'] = $datas['head_url'];
                            $user_save['nickname'] = $this->filterNickname($datas['nickname']);
                            $user_where['openid'] = $cache_data['openid'];
                            $user_id=db('user')->where($user_where)->save($user_save);
                            if($user_id){

                                    $cache_data['head_url'] = $datas['head_url'];
                                    $cache_data['nickname'] = $this->filterNickname($datas['nickname']);
                                    $cache_data_key = $token."_info";
                                    Cache::set($cache_data_key,$cache_data,3600);

                            }else{        
                                    $data['status'] = 0;
                                    $data['data'] = '';
                                    echo json_encode($data);exit;  
                            }

                        }
                    }else{

                            $data['status'] = 0;
                            $data['data'] = '';
                            echo json_encode($data);exit;  
                    }

            }else{

                    $cache_data['head_url'] = $datas['avatarUrl'];
                    $cache_data['nickname'] = $datas['nickName'];                           
                    $where_user['openid'] = $datas['openId'];
                    $user_arr = db('user')->where($where_user)->find();
                    if(empty($user_arr)){

                        $user_insert=array();
                        $user_insert['create_time']=time();
                        $user_insert['head_url'] = $datas['avatarUrl'];
                        $user_insert['nickname'] = $this->filterNickname($datas['nickName']);
                        $user_insert['openid'] = $datas['openId'];
                        $user_id=db('user')->insert($user_insert);

                        if($user_id){

                            $cache_data['head_url'] = $user_insert['head_url'];
                            $cache_data['nickname'] = $user_insert['nickname'];
                            $cache_data['uid'] = $user_arr['user_id'];

                            $cache_data_key = $token."_info";
                            Cache::set($cache_data_key,$cache_data,3600);  
                        }
                        else
                        {
                            $data['status'] = 0;
                            $data['data'] = '';
                            echo json_encode($data);exit;  
                        }


                    }else{

                            $cache_data['head_url'] = $user_arr['head_url'];
                            $cache_data['nickname'] = $user_arr['nickname'];
                            $cache_data['uid'] = $user_arr['user_id'];
                            $cache_data_key = $token."_info";
                            Cache::set($cache_data_key,$cache_data,3600);  

                    }


            }

        } else {

            //解密失败
            $data['status'] = 0;
            $data['data'] = '';
            echo json_encode($data);exit;  
        }


        //写日志 并且记录到日志表
        @file_put_contents($dir_path."/test.log", date('Y-m-d H:i:s') . ' openid ' . $datas['openId'] . PHP_EOL, FILE_APPEND);
        $insert_data=array();
        $insert_data['time'] = time();
        $insert_data['openid'] =  $datas['openId'];
        @db('logs')->insert($insert_data);

        $return_data['status'] = 1;
        $return_data['uid'] = $cache_data['uid'];
        $return_data['head_url'] = $cache_data['head_url'];
        $return_data['nickname'] = $cache_data['nickname'];
        echo json_encode($return_data);exit; 

    }

    //过滤nickname 标签
    public function filterNickname($nickname) {
        $nickname = preg_replace('/[\x{1F600}-\x{1F64F}]/u', '', $nickname);
        $nickname = preg_replace('/[\x{1F300}-\x{1F5FF}]/u', '', $nickname);
        $nickname = preg_replace('/[\x{1F680}-\x{1F6FF}]/u', '', $nickname);
        $nickname = preg_replace('/[\x{2600}-\x{26FF}]/u', '', $nickname);
        $nickname = preg_replace('/[\x{2700}-\x{27BF}]/u', '', $nickname);
        $nickname = str_replace(array('"', '\''), '', $nickname);

        return addslashes(trim($nickname));
    }



}
Wxbizdatacrypt.php
<?php

/**
 * 对微信小程序用户加密数据的解密示例代码.
 *
 * @copyright Copyright (c) 1998-2014 Tencent Inc.
 */

namespace app\api\controller;
use app\api\controller\Base;
use think\Model;
use think\Db;
use think\Cache;

include_once	"ErrorCode.php";

class Wxbizdatacrypt
{
    private $appid;
	private $sessionKey;

	/**
	 * 构造函数
	 * @param $sessionKey string 用户在小程序登录后获取的会话**
	 * @param $appid string 小程序的appid
	 */
	public function __construct( $appid, $sessionKey)
	{
		$this->sessionKey = $sessionKey;
		$this->appid = $appid;
	}


	/**
	 * 检验数据的真实性,并且获取解密后的明文.
	 * @param $encryptedData string 加密的用户数据
	 * @param $iv string 与用户数据一同返回的初始向量
	 * @param $data string 解密后的原文
     *
	 * @return int 成功0,失败返回对应的错误码
	 */
	public function decryptData( $encryptedData, $iv, &$data )
	{
		if (strlen($this->sessionKey) != 24) {
			return ErrorCode::$IllegalAesKey;
		}
		$aesKey=base64_decode($this->sessionKey);

        
		if (strlen($iv) != 24) {
			return ErrorCode::$IllegalIv;
		}
		$aesIV=base64_decode($iv);

		$aesCipher=base64_decode($encryptedData);

		$result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);

		$dataObj=json_decode( $result );
		if( $dataObj  == NULL )
		{
			return ErrorCode::$IllegalBuffer;
		}
		if( $dataObj->watermark->appid != $this->appid )
		{
			return ErrorCode::$IllegalBuffer;
		}
		$data = $result;
		return ErrorCode::$OK;
	}

}


ErrorCode.php

<?php
namespace app\api\controller;
use app\api\controller\Base;
use think\Model;
use think\Db;
use think\Cache;
/**
 * error code 说明.
 * <ul>

 *    <li>-41001: encodingAesKey 非法</li>
 *    <li>-41003: aes 解密失败</li>
 *    <li>-41004: 解密后得到的buffer非法</li>
 *    <li>-41005: base64加密失败</li>
 *    <li>-41016: base64解密失败</li>
 * </ul>
 */
class ErrorCode
{
	public static $OK = 0;
	public static $IllegalAesKey = -41001;
	public static $IllegalIv = -41002;
	public static $IllegalBuffer = -41003;
	public static $DecodeBase64Error = -41004;
}

?>

结构目录如下

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )


代码写的比较烂 只要有错误 全都返回状态为0 其实这里应该根据多种情况返回不同的错误代码 或者错误信息描述 

这里就是简单实现的功能 没有完善 数据库查询也直接在c层写了 有洁癖和完美的 可以在model层自己重新写

=================================我是分割线==============================

小程序前端代码如下 

基于tp5小程序登录的实现 demo版本 获取code 返回token 解密微信数据信息 和验证数据来源真实性(包含小程序前端和php后端代码 )

index.js

//index.js
//获取应用实例
const app = getApp()

Page({
  data: {
    code:null,
    token:null,
    tk:null
  },
  //登录获取code
  login:function(){
    var that=this
      wx.login({
        success:function(res){
          console.log(res.code);
          that.setData({
            code: res.code
          }), 
          wx.request({
            url: 'http://www.tpxcx.com/api/login/getcode',
            method: "post",
            header: {
              "Content-Type": "application/x-www-form-urlencoded"
            },
            data: {
              code: res.code
            },
            success: function (res) {
              if (res.data.status == 1) {
  
                that.setData({
                  token: res.data.token
                })
                console.log("token=" + that.data.token);
              } else {
                console.log("请求token失败s");
              }
            }
          })

        }
      })

      


  },

  tk:function()
  {
    var that = this
    wx.getUserInfo({
      success: function (res) {
        console.log(res.userInfo);
        console.log(res.encryptedData);
        console.log(res.iv);

        wx.request({
          url: 'http://www.tpxcx.com/api/login/login',
          method: "post",
          header: {
            "Content-Type": "application/x-www-form-urlencoded"
          },
          data: {
            token: that.data.token,
            encryptedData: res.encryptedData,
            signature: res.signature,
            iv: res.iv,
            rawData: res.rawData
          },
          success: function (res) {
            if (res.data.status == 1) {

            } else {

            }
          }
        })




      }




    })
  },
  share_test: function () {
    var that = this
    wx.getUserInfo({
      success: function (res) {
        console.log(res.userInfo);
        console.log(res.encryptedData);
        console.log(res.iv);

        wx.request({
          url: 'http://www.tpxcx.com/api/banner/getbanner',
          //url: 'http://www.tpxcx.com/api/catedetail/get_detail_one ',
          method: "post",
          header: {
            "Content-Type": "application/x-www-form-urlencoded"
          },
          data: {
            token: that.data.token,
           //uid:5,
           id:23
          },
          success: function (res) {
            if (res.data.status == 1) {

            } else {

            }
          }
        })




      }




    })
  }

})

index.wxml

<button bindtap="login">登录</button>
<button bindtap="tk">token</button>
<button bindtap="share_test">分享测试返回头像和昵称</button>


程序里用到的一些公共方法curl啥的 代码如下 

<?php

//二维数组拼接,拼接value 去重
function arr_unique($arr2d){
	foreach ($arr2d as $k=>$v) {
		$v=join(',',$v);
		$temp[]=$v;
	}
	if($temp){
		$temp=array_unique($temp);
		foreach ($temp as $k=>$v) {
			$temp[$k]=explode(',', $v);
		}

		return $temp;
	}
	

}



/**
 * @param string $url post请求地址
 * @param array $params
 * @return mixed
 */
function curl_post($url, array $params = array())
{
    $data_string = json_encode($params);
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
    curl_setopt(
        $ch, CURLOPT_HTTPHEADER,
        array(
            'Content-Type: application/json'
        )
    );
    $data = curl_exec($ch);
    curl_close($ch);
    return ($data);
}

function curl_post_raw($url, $rawData)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, 0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $rawData);
    curl_setopt(
        $ch, CURLOPT_HTTPHEADER,
        array(
            'Content-Type: text'
        )
    );
    $data = curl_exec($ch);
    curl_close($ch);
    return ($data);
}

/**
 * @param string $url get请求地址
 * @param int $httpCode 返回状态码
 * @return mixed
 */
function curl_get($url, &$httpCode = 0)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    //不做证书校验,部署在linux环境下请改为true
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
    $file_contents = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    return $file_contents;
}

function getRandChar($length)
{
    $str = null;
    $strPol = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
    $max = strlen($strPol) - 1;

    for ($i = 0;
         $i < $length;
         $i++) {
        $str .= $strPol[rand(0, $max)];
    }

    return $str;
}