事先准备工作

1.申请一个小程序,申请地址:传送门

2.仔细阅读小程序的用户授权登陆官方文档:《用户授权登陆的流程》

3.仔细阅读微信用户数据解密的相关文档:《用户数据解密说明文档》

4.在小程序后台配置好相应的后端请求地址,路径是:开发---->开发设置,如图

5.小程序如果需要做多个小程序的打通,还需要在微信开放平台绑定到开发者账号下面, 如果不需要union_id请忽略

6.服务端准备一个用户授权的接口,假设接口链接为http://test.dev.com/user/auth...,此接口接受如下参数

code:微信登陆接口返回的登陆凭证,用户获取session_key

iv:微信小程序登陆接口返回的向量,用于数据解密

encrypted_data : 微信获取用户信息接口的返回的用户加密数据,用于后端的接口解析

signature加密数据

接口返回的数据如下

{

"errcode": 200,

"msg": "SUCCESS",

"data": {

"uid": 34098,

"unionid": "xxx",

}

}

6.建表

1)用户表,其中比较重要的字段是union_id,因为我们是有多个小程序和公众号,因此使用这个来区分唯一的用户编号

DROP TABLE IF EXISTS `jz_wxa_user`;

CREATE TABLE `jz_wxa_user` (

`id` int(10) unsigned NOT NULL AUTO_INCREMENT,

`uid` bigint(18) DEFAULT NULL,

`openid` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT 'openid',

`user_name` varchar(100) CHARACTER SET utf8mb4 DEFAULT '',

`nick_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '用户昵称',

`sex` enum('0','1') CHARACTER SET utf8 DEFAULT '1' COMMENT '性别',

`avatar` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '用户头像',

`province` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '省份',

`city` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '城市',

`country` varchar(100) CHARACTER SET utf8 DEFAULT NULL COMMENT '国家',

`wx_union_id` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '公众平台的唯一id',

`from_url` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '来源url',

`created_at` timestamp NULL DEFAULT NULL,

`updated_at` timestamp NULL DEFAULT NULL,

`from_appid` varchar(30) COLLATE utf8mb4_unicode_ci DEFAULT 'wx95fc895bebd3743b' COMMENT '来源appid',

`wx_header` varchar(150) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '微信头像',

`gh_openid` varchar(60) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '微信公众号openid',

`phone` varchar(30) CHARACTER SET utf8 DEFAULT '' COMMENT '手机号码',

PRIMARY KEY (`id`),

KEY `idx_uid_union_id` (`uid`,`wx_union_id`)

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

实现步骤

用户授权时序图

关键代码

小程序端

小程序端的获取用户信息流程

1)调用login方法获取code

2)调用getUserInfo方法获取用户的加密数据

3)调用后端的用户授权接口将用户信息保存到服务端

4)保存后端接口返回的uid和unionid到localstorage中,作为全局参数

获取用户的授权信息

getUid:function(cf){

var that = this

wx.login({

success: function (ress) {

var code = ress.code

wx.getUserInfo({

withCredentials: true,

success: function (res) {

that.globalData.userInfo = res.userInfo;

that.authorize(code, res.signature, res.iv, res.rawData, res.encryptedData, cf)

}

})

}

})

},

authorize: function (code, signature, iv, rawData, encryptedData, cf) {

var that =this

var dataobj = {

code: code,

signature: signature,

iv: iv,

raw_data: rawData,

encrypted_data: encryptedData

}

console.log("code:",code)

var param = JSON.stringify(dataobj)

param = that.Encrypt(param)

var url = that.data.API_DOMAIN2 + "/user/authorization?param=" + param

wx.request({

url: url,

method: "GET",

header: {

'content-type': 'application/json'

},

success: function (res) {

if (res.data.errcode == 200) {

wx.hideToast()

wx.setStorage({

key: "uid",

data: res.data.data.uid,

success: function () {

if (cf) {

typeof cf == "function" && cf(res.data.data.uid)

}

}

})

} else {

that.exceptionHandle('uid', url, res.data.errcode, res.data.msg)

}

}

})

},

服务端

入口方法

/**

* api接口开发

* 获取详情的接口

* @param $uid 用户编号

* @param $iv 向量

* @param $encryptedData 微信加密的数据

* @param $rawData 判断是否为今天

* @param $signature 签名

* @return array

*/

public static function authorization($appid,$appsecret,$code,$iv,$encryptedData,$rawData,$signature){

$result = self::decodeWxData($appid,$appsecret,$code,$iv,$encryptedData);

if($result['errcode'] != 200){

return $result;

}

//处理微信授权的逻辑

$wxUserData = $result['data'];

error_log("authorization data=============>");

error_log(json_encode($wxUserData));

$uid = WxaUserService::regWxaUser($wxUserData);

$data['uid'] = $uid['uid'];

$data['unionid'] = $uid['unionid'];

$result['data'] = $data;

return $result;

}

/**

* 解密微信的数据

* @param $code wx.login接口返回的code

* @param $iv wx.getUserInfo接口或者wx.getWeRunData返回的iv

* @param $encryptedData wx.getUserInfo接口或者wx.getWeRunData返回的加密数据

* @return array

*/

public static function decodeWxData($appid,$appsecret,$code,$iv,$encryptedData){

$sessionKeyUrl = sprintf('%s?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code',config('param.wxa_user_info_session_key_url'),$appid,$appsecret,$code);

$rtnJson = curlRequest($sessionKeyUrl);

$data = json_decode($rtnJson,true);

error_log('authorization wx return data========>');

error_log($rtnJson);

if(isset($data['errcode'])){

return $data;

}

$sessionKey = $data['session_key'];

$wxHelper = new WxBizDataHelper($appid,$sessionKey,$encryptedData,$iv);

$data['errcode'] = 200;

$data['data'] = [];

if(!$wxData = $wxHelper->getData()){

$data['errcode'] = -1;

}else{

error_log('current wx return data is =========>'.json_encode($wxData));

$data['data'] = $wxData;

}

return $data;

}

保存用户信息的方法

/**

* 保存用户信息的方法

* @param $wxaUserData

* @param $regFromGh 表示是否从公众号进行注册

*/

public function regWxaUser($wxaUserData,$regFromGh = false)

{

$value = $wxaUserData['unionId'];

$key = getCacheKey('redis_key.cache_key.zset_list.lock') . $value;

$newExpire = RedisHelper::getLock($key);

$data = $this->storeWxaUser($wxaUserData,$regFromGh);

RedisHelper::releaseLock($key, $newExpire);

return $data;

}

/**

* 保存信息

* @param $wxaUserData

* @return mixed

*/

public function storeWxaUser($wxaUserData,$regFromGh = false)

{

$wxUnionId = $wxaUserData['unionId'];

if (!$user = $this->getByWxUnionId($wxUnionId)) {

$getAccountDataStartTime = time();

//这里是因为需要统一账户获取uid,所以这个是用户中心的接口,如果没有这个流程,则直接使用数据

if($accountData = AccountCenterHelper::regWxaUser($wxaUserData)){

$getAccountDataEndTime = time();

$accountRegTime = $getAccountDataEndTime - $getAccountDataStartTime;

error_log("reg user spend time is ===================>" . $accountRegTime);

$user = [

'uid' => $accountData['uid'],

'user_name' => $accountData['user_name'],

'nick_name' => $wxaUserData['nickName'],

'sex' => $accountData['sex'],

'wx_union_id' => $accountData['wx_union_id'],

'avatar' => isset($accountData['avatar'])?$accountData['avatar']:"",

'from_appid' => $accountData['from_appid'],

'province' => $wxaUserData['province'],

'city' => $wxaUserData['city'],

'country' => $wxaUserData['country'],

'openid' => $wxaUserData['openId'],

'wx_header' => isset($wxaUserData['avatarUrl'])?$wxaUserData['avatarUrl']:"",

'gh_openid' => $regFromGh?$wxaUserData['openId']:"",

];

error_log("insert data=============>" . json_encode($user));

$user = $this->store($user);

$regApiUserEndTime = time();

error_log(" reg api user spend time================>" . ($regApiUserEndTime - $getAccountDataEndTime));

error_log(" after insert data=============>" . json_encode($user));

}

}else{

if(!$user['wx_header']){

$updateData = [

'id' => $user['id'],

'uid' => $user['uid'],

'wx_header' => $wxaUserData['avatarUrl'],

];

$this->update($updateData);

}

//同步用户的openid

if($wxaUserData['openId'] != $user['openid']){

$updateData = [

'id' => $user['id'],

'uid' => $user['uid'],

'openid' => $wxaUserData['openId'],

];

$this->update($updateData);

}

}

$data['uid'] = $user['uid'];

$data['unionid'] = $wxUnionId;

return $data;

}

根据unionid获取用户信息

/**

* 根据unionid获取用户信息

*/

public function getByWxUnionId($unionId)

{

$cacheKey = getCacheKey('redis_key.cache_key.wxa_user.info') . $unionId;

$value = $this->remember($cacheKey, function () use ($unionId) {

$userInfo = WxaUser::where('wx_union_id', $unionId)->first();

$userInfo = $this->compactUserInfo($userInfo);

return $userInfo;

});

return $value;

}

WxBizDataHelper工具类

/**

* Created by PhpStorm.

* User: Auser

* Time: 11:17

*/

namespace App\Http\Base\Wx;

class WxBizDataHelper

{

private $appid;

private $seesionKey ;

private $encryptedData;

private $iv;

public function __construct($appid, $sessionKey,$encryptedData, $iv)

{

$this->appid = $appid;

$this->seesionKey = $sessionKey;

$this->encryptedData = $encryptedData;

$this->iv = $iv;

}

public function getData(){

$pc = new WXBizDataCrypt($this->appid, $this->seesionKey);

$json = '';

$errCode = $pc->decryptData($this->encryptedData, $this->iv, $json);

$data = [];

if ($errCode == 0) {

$data = json_decode($json,true);

}

return $data;

}

}

WXBizDataCrypt工具类

/**

* Created by PhpStorm.

* User: Auser

* Time: 10:38

*/

namespace App\Http\Base\Wx;

use App\Http\Base\Wx\Prpcrypt;

use App\Http\Base\Wx\ErrorCode;

use App\Http\Base\Wx\PKCS7Encoder;

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);

$pc = new Prpcrypt($aesKey);

$result = $pc->decrypt($aesCipher,$aesIV);

if ($result[0] != 0) {

return $result[0];

}

$dataObj=json_decode( $result[1] );

if( $dataObj == NULL )

{

return ErrorCode::$IllegalBuffer;

}

if( $dataObj->watermark->appid != $this->appid )

{

return ErrorCode::$IllegalBuffer;

}

$data = $result[1];

return ErrorCode::$OK;

}

}

Prpcrypt工具类

/**

* Created by PhpStorm.

* User: Auser

* Time: 10:55

*/

namespace App\Http\Base\Wx;

class Prpcrypt

{

public $key;

public function __construct($key)

{

$this->key = $key;

}

/**

* 对密文进行解密

* @param string $aesCipher 需要解密的密文

* @param string $aesIV 解密的初始向量

* @return string 解密得到的明文

*/

public function decrypt($aesCipher, $aesIV)

{

try {

$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

mcrypt_generic_init($module, $this->key, $aesIV);

//解密

$decrypted = mdecrypt_generic($module, $aesCipher);

mcrypt_generic_deinit($module);

mcrypt_module_close($module);

} catch (Exception $e) {

return array(ErrorCode::$IllegalBuffer, null);

}

try {

$result = PKCS7Encoder2::decode($decrypted);

} catch (Exception $e) {

//print $e;

return array(ErrorCode::$IllegalBuffer, null);

}

return array(0, $result);

}

}

ErrorCode状态代码类

/**

* Created by PhpStorm.

* User: Auser

* Time: 10:33

*/

namespace App\Http\Base\Wx;

class ErrorCode

{

public static $OK = 0;

public static $IllegalAesKey = -41001;

public static $IllegalIv = -41002;

public static $IllegalBuffer = -41003;

public static $DecodeBase64Error = -41004;

}

微信小程序php java_PHP实现微信小程序用户授权的工具类相关推荐

  1. 微信小程序php java_PHP实现微信小程序用户授权的工具类示例

    事先准备工作 1.申请一个小程序,申请地址:传送门 2.仔细阅读小程序的用户授权登陆官方文档: <用户授权登陆的流程> 3.仔细阅读微信用户数据解密的相关文档: <用户数据解密说明文 ...

  2. php对接小程序获取表单,PHP实现微信小程序用户授权的工具类

    事先准备工作 1.申请一个小程序,申请地址:传送门 2.仔细阅读小程序的用户授权登陆官方文档:<用户授权登陆的流程> 3.仔细阅读微信用户数据解密的相关文档:<用户数据解密说明文档& ...

  3. Flutter - 一个fultter练习项目(仿写微信UI、实现一些常用效果、封装通用组件和工具类)

    demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新,请前往github查看最新代码 pwd:123456 代码不定期更新 注:Flut ...

  4. 微信小程序人脸核身---快速入门到实战(附开发工具类,复制即用)

    文章目录 一.基本介绍 1.概述 2.功能特点 3.使用场景 二.术语概述 基础参数说明 DetectAuth(实名核身鉴权) GetDetectInfo(获取实名核身结果信息) 三.基本接口说明使用 ...

  5. 人脸核身 微信h5_微信小程序人脸核身---快速入门到实战(附开发工具类,复制即用)...

    这里咱们使用腾讯云的人脸核身来给你们作一个基础的介绍和使用java 1.基本介绍 1.概述 人脸核身:通常是对一组对用户身份信息真实性进行验证审核的服务套件提供各种认证功能模块,包含证件 OCR 识别 ...

  6. 首份小程序广告投放价值榜单发布:游戏、工具类小程序占主导地位

    2018年3月小程序广告正式开放内测,所有类目小程序均可进行广告投放.随后众多品牌小程序纷纷开放小程序广告,近日第三方小程序开发工具即速应用和 精硕科技集团 赋能智慧商业的数据智能技术提供商nEqua ...

  7. 用c#开发微信(2)扫描二维码,用户授权后获取用户基本信息 (源码下载)

    本文将介绍基于Senparc.Weixin微信开发框架来实现网页授权来获取用户基本信息.先生成包含授权及回调url信息的二维码:用户用微信扫描之后,被要求授权以获取Ta的用户基本信息:用户授权后,通过 ...

  8. 微信小程序弹出用户授权弹窗,微信小程序引导用户授权,获取位置经纬度

    我们在开发小程序时,有些操作必须让用户授权.比如我们获取用户位置,需要用户授权位置信息.授权操作我们需要给用户弹窗提示,在用户禁用某些权限时,又要引导用户去设置页开启相应权限.我们这里就以获取经纬度为 ...

  9. 推荐3个生活工具类的小程序,非常实用哦!

    现在只要通过小程序,就可以解决80%的APP功能需求了,只是很多人都不太清楚有哪些实用的小程序.今天,给大家推荐3个生活工具类的小程序,非常实用哦! 1.待办事项清单 办事项清单小程序是一个比较实用的 ...

最新文章

  1. 智能生产的现状与未来!
  2. c# 获取excel单元格公式结果_excel公式应用技巧:文字和数字混合的单元格,如何求和?...
  3. 第二轮“双一流”名单:这 44 所高校有调整!
  4. 网络工程师交换试验手册之十八:SWITCH的基本配置
  5. php支持cs吗,关于composer、phpmd和phpcs于windows中的安装与使用方法
  6. Spring之AOP详解
  7. 【彻底搞清楚javascript中的require、import和export 】
  8. Java基础之路--引用数据类型之数组
  9. 和 远程文件夹同步_云同步实操(2)安卓端同步文件夹2
  10. iPhone11用第三方的快充,电池健康度会下降很快吗?
  11. yii2GridView的简单使用
  12. 基于品类关系,虚拟类目如何建设?
  13. Asp.Net Repeater控件绑定泛型ListT的用法
  14. 各种二进制特征提取算子(ORB 、BRIEF 、 FREAK、 BRISK)
  15. 2022年数据库行业展望
  16. 线性方程组解的几何意义
  17. 喝咖啡写脚本,顺便再加一点点CSS语法糖 1.选择环境
  18. T 基础 高数 上:函数
  19. 数据流标准差计算方法-不用事先计算均值
  20. PHP学习:PHP+Apache 安装/配置

热门文章

  1. 【Android】Fresco图片加载框架(二)————Producer
  2. javascript图片轮换
  3. sql 获取第10到20个记录
  4. Oracle TNS-12535: TNS: 操作超时
  5. 莫比乌斯带catia建模_用sw2018制作莫比乌斯环图文教程
  6. Python实现中文文档的简体与繁体互相转换
  7. Python数据分析库pandas高级接口dt和str的使用
  8. Python基于值的内存管理真相
  9. Python版双链表结构与有关操作
  10. react 更新input 默认值setfieldsvalue_值得收藏的React知识点查漏补缺