.Net之微信小程序获取用户UnionID的实现

前言:

在实际项目开发中我们经常会遇到账号统一的问题,如何在不同端或者是不同的登录方式下保证同一个会员或者用户账号唯一(便于用户信息的管理)。这段时间就有一个这样的需求,之前有个客户做了一个微信小程序商城(店主端的),然后现在又要做一个会员购物端的小程序商场。首先之前用户登录凭证都是使用微信openid来做的唯一标识,而现在客户需求是要做到用户在会员端小程序跳转到到店主端小程序假如之前该用户微信是在店主端审核通过的用户则不需要在进行资料提交审核操作,直接登录。所以,所以我们使用了UnionID来进行关联,如下是我们现在项目的基本流程(画的丑莫见怪)。

说说UnionID机制:

如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 UnionID 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 UnionID 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。

官方UnionID机制详细说明:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html

微信开放平台绑定小程序流程:

登录微信开放平台— 管理中心 — 小程序 — 绑定小程序(直接使用微信官方图)

微信小程序获取UnoinID的两种方式

调用接口wx.getUserInfo,从解密数据(encryptedData)中获取 UnionID(推荐使用):

推荐使用原因:无需关注微信公众号即可获取到UnionID。

调用接口wx.getUserInfo前提:用户允许授权获取用户信息!

开发者后台校验与解密开放数据:

微信为了保证用户信息,把用户通过wx.getUserInfo接口获取到的相关敏感信息进行了加密。加密方式对称加密(后面会提到),首先我们需要通过微信小程序登录流程获取到用户的session_key(会话密钥),然后我们可以报获取到的会话密钥使用缓存存起来,在通过用户授权获取用户相关信息,如下是用户授权成功获取到的用户信息:

基本流程图如下:

(encryptedData)加密数据解密算法:

开发者如需要获取敏感数据,需要对接口返回的加密数据(encryptedData)进行对称解密。 解密算法如下:

  1. 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
  2. 对称解密的目标密文为 Base64_Decode(encryptedData)。
  3. 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
  4. 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回

很遗憾的是微信居然没有为我们大.Net提供解密算法demo,实属让人不算,最后自己根据网上的资料还是配上了符合微信对称加密的解密算法。

代码实现:

首先关于session_key(会话密钥)的获取,请看下面的wx.login+code2Session 方式

调用接口wx.getUserInfo获取encryptedData(加密数据)和iv(初始向量):

// 用户已经授权
wx.getUserInfo({
success: function(res) {
console.log(res);
var userInfo = res.userInfo //用户基本信息
let sessionKey = wx.getStorageSync("session_key");//临时会话密钥,通过小程序登录流程获取到的
//请求.net webapi解密接口
wx.request({
 url: 'https://www.xxxtest.com/api/User_oAuth/DecryptSensitiveData',
data: {
sessionKey:sessionKey,
encryptedData:res.encryptedData,
iv:res.iv
},
 header: {
'content-type': 'application/json' // 默认值
},
success (res) {
//解密返回过来的UnionID
console.log(res.data)
}
})
}
})
})

.Net WebApi 解密数据接口:

/// <summary>
  /// 解密微信对称加密数据,获取用户联合运营编号
  /// </summary>
  /// <param name="sessionKey">临时会话秘钥</param>
  /// <param name="encryptedData">微信用户敏感加密数据</param>
  /// <param name="iv">解密初始向量</param>
  /// <returns></returns>
  [HttpGet]
  public IHttpActionResult DecryptSensitiveData(string sessionKey,string encryptedData,string iv)
  {
   try
   {
    var getUnionId=DecryptByAesBytes(encryptedData, sessionKey, iv);

    return Json(new { code =1, msg="解密成功",result= getUnionId });
   }
   catch (Exception ex)
   {
    return Json(new { code = 0, msg = "解密失败,原因:"+ex.Message });
   }
  }

  #region AES对称解密
  /// <summary>
  /// AES解密
  /// </summary>
  /// <param name="encryptedData">待解密的字节数组</param>
  /// <param name="sessionKey">解密密钥字节数组</param>
  /// <param name="iv">IV初始化向量字节数组</param>
  /// <param name="cipher">运算模式</param>
  /// <param name="padding">填充模式</param>
  /// <returns></returns>
  private static string DecryptByAesBytes(string encryptedData, string sessionKey, string iv)
  {
   try
   {
    //非空验证
    if (!string.IsNullOrWhiteSpace(encryptedData) && !string.IsNullOrWhiteSpace(sessionKey) && !string.IsNullOrWhiteSpace(iv))
    {
     var decryptBytes = Convert.FromBase64String(encryptedData.Replace(' ', '+'));
     var keyBytes = Convert.FromBase64String(sessionKey.Replace(' ', '+'));
     var ivBytes = Convert.FromBase64String(iv.Replace(' ', '+'));

     var aes = new AesCryptoServiceProvider
     {
      Key = keyBytes,
      IV = ivBytes,
      Mode = CipherMode.CBC,
      Padding = PaddingMode.PKCS7
     };

     var outputBytes = aes.CreateDecryptor().TransformFinalBlock(decryptBytes, 0, decryptBytes.Length);

     var decryptResult = Encoding.UTF8.GetString(outputBytes);
     dynamic decryptData = JsonConvert.DeserializeObject(decryptResult, new { unionid = "" }.GetType());
     JJHL.Utility.Loghelper.WriteLog("AES对称解密结果为:" + decryptResult);
     return decryptData.unionid;
    }
    else
    {
     return "";
    }
   }
   catch (Exception e)
   {
    JJHL.Utility.Loghelper.WriteLog("AES对称解密失败原因:" + e.Message);
    return "";
   }
  }

  #endregion

所遇异常:参数使用Convert.FromBase64String转化时,提示“Base-64字符数组的无效长度” 的问题:

原因:加密参数中的"+"通过地址栏传过来时,后台会解析为空格(遇到的概率比较小)。

解决:最好的做法是 使用encryptedData.Replace("+", "%2B")先将空格编码,然后再作为参数传给另一页面传递,这样页面在提取参数时才会将“%2B”解码为加号.但这儿为了简化,将空格直接还原为"+"或者是直接在后台将空格替换为“+”encryptedData.Replace(' ', '+');

直接通过wx.login+code2Session获取到该用户 UnionID:

其实这个方式就是实现了小程序的登录流程,微信官方详细说明:

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

优点:无需用户授权。

前提:用户需要关注该微信公众号。

小程序端调用接口wx.login获取code凭证,在通过请求auth.code2Session接口获取用户信息(UnionID,openid,session_key会话密钥)两种方式:

1.直接通过wx.login请求到code凭证后,在请求该地址获取用户信息:

GET:https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

详细说明请看微信官方文档(代码略):https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

2.通过请求wx.login获取code凭证,在向.net webapi后端请求code2Session接口:

原因:因为我们需要对获取的用户信息做相关业务逻辑处理。

微信小程序端代码:

 代码如下:

/***封装用户promise登录,通过code凭证获取用户信息(UnionID,openid,session_key会话密钥)*/userLogin: function() {var that = this;//定义promise方法return new Promise(function(resolve, reject) {//调用登录接口wx.login({success: function(res) {if (res.code) {console.log("用户登录授权code为:" + res.code);//调用wx.request请求传递code凭证换取用户openid,并获取后台用户信息wx.request({url: 'https://www.xxxx.xxx.api/User_oAuth/GetUserInfo',//后台请求用户信息方法data: {code: res.code //code凭证},header: {'content-type':'application/json' // 默认值},success(res) {console.log(res.data)if (res.data.errcode == 0) {//存入session缓存中console.log(res.data.openid);//微信用户唯一标识console.log(res.data.UnionID);//微信开发平台联合IDconsole.log(res.data.session_key);//会话密钥
//***注意****
//注意:这里是直接把session_key缓存起来,在上面wx.getUserInfo会使用到
wx.setStorageSync("session_key",res.data.session_key);

[code]//promise机制放回成功数据
resolve(res.data);
} else
{ reject('error'); }
}, fail: function(res)
{
reject(res);
wx.showToast({ title: '系统错误' })
}, complete: () => { } //complete接口执行后的回调函数,无论成功失败都会调用
}) } else
{
reject("error");
}}
})})}[/code

.Net WebApi 请求用户信息接口:

/// <summary>
  /// 获取用户信息
  /// </summary>
  /// <param name="code">信息数据code凭证</param>
  /// <returns></returns>
  [HttpGet]
  public IHttpActionResult GetUserInfo(string code)
  {
   string AppSecret = "小程序秘钥";
   string AppId = "应用程序标识";

   try
   {
    //请求目标地址和参数(authorization_code授权类型,此处只需填写 authorization_code)
    string OauthUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + AppId + "&secret=" + AppSecret + "&js_code=" + code + "&grant_type=authorization_code";//序列化解析数据
    var Result = HttpGet(OauthUrl);

    return Json(new { openid = Result.openid, errcode = Result.errcode, UnionID = Result.unionid, session_key = Result.session_key });
   }
   catch (Exception ex)
   {

    return Json(new { errcode = 1, msg = "获取用户信息失败" + ex.Message });
   }
  }

  /// <summary>
  /// 请求code2Session接口获取用户信息
  /// </summary>
  /// <param name="requestDataAndUrl">目标地址和参数</param>
  /// <returns></returns>
  public WxOauthModle HttpGet(string requestDataAndUrl)
  {
   HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestDataAndUrl);
   request.Method = "GET";
   request.ContentType = "text/html;charset=UTF-8";
   HttpWebResponse response = (HttpWebResponse)request.GetResponse();
   Stream myResponseStream = response.GetResponseStream();
   StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.UTF8);
   string retString = myStreamReader.ReadToEnd();
   myStreamReader.Close();
   myResponseStream.Close();

   return JsonConvert.DeserializeObject<WxOauthModle>(retString);
  }

  public class WxOauthModle
  {
   /// <summary>
   /// 用户唯一标识
   /// </summary>
   public string openid { get; set; }

   /// <summary>
   /// 会话秘钥
   /// </summary>
   public string session_key { get; set; }

   /// <summary>
   /// 联立编号
   /// </summary>
   public string unionid { get; set; }

   /// <summary>
   /// 错误码
   /// </summary>
   public int errcode { get; set; }

   /// <summary>
   /// 错误信息
   /// </summary>
   public string errmsg { get; set; }
  }

关于微信网页开发通过UnionID机制解决用户在不同公众号,或在公众号、移动应用之间帐号统一问题:

详情说明请点击:https://www.jb51.net/article/168982.htm

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 详解微信小程序-获取用户session_key,openid,unionid - 后端为nodejs

    微信小程序-获取用户session_key,openid,unionid - 后端为nodejs8.0+ 步骤: 1.通过wx.login接口获取code既jscode,传递到后端: 2.后端请求 https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code 地址,就能获取到openid和unionid. 小程序接

  • .Net之微信小程序获取用户UnionID的实现

    前言: 在实际项目开发中我们经常会遇到账号统一的问题,如何在不同端或者是不同的登录方式下保证同一个会员或者用户账号唯一(便于用户信息的管理).这段时间就有一个这样的需求,之前有个客户做了一个微信小程序商城(店主端的),然后现在又要做一个会员购物端的小程序商场.首先之前用户登录凭证都是使用微信openid来做的唯一标识,而现在客户需求是要做到用户在会员端小程序跳转到到店主端小程序假如之前该用户微信是在店主端审核通过的用户则不需要在进行资料提交审核操作,直接登录.所以,所以我们使用了UnionID来

  • Thinkphp5微信小程序获取用户信息接口的实例详解

    Thinkphp5微信小程序获取用户信息接口的实例详解 首先在官网下载示例代码, 选php的, 这里有个坑 官方的php文件,编码是UTF-8+的, 所以要把文件改为UTF-8 然后在Thinkphp5 extend文件夹下建立Wxxcx命名空间,把官方的几个类文件放进去(这里要注意文件夹名, 命名空间名, 类名的, 大小写,一定要一样,官方的文件名和类名大小写不一样) 然后是自己的thinkphp接口代码: <?php /** * Created by PhpStorm. * User: le

  • 微信小程序--获取用户地理位置名称(无须用户授权)的方法

    在本文 微信小程序--获取用户地理位置名称(无须用户授权) 之前需要先看看 微信小程序-获取用户session_key,openid,unionid - 后端为nodejs 代码封装是在上文添加的. 准备 1.在http://lbs.qq.com/网站申请key 2.在微信小程序后台把apis.map.qq.com添加进request合法域名 效果 添加封装 /** * 发起网络请求 * @param {string} url * @param {object} params * @return

  • 微信小程序获取用户信息并保存登录状态详解

    前言 微信小程序的运行环境不是在浏览器下运行的.所以不能以cookie来维护登录态.下面我就来说说我根据官方给出的方法来写出的维护登录态的方法吧. 一.登录态维护 官方的文档地址:https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html#wxloginobject 通过 wx.login() 获取到用户登录态之后,需要维护登录态.开发者要注意不应该直接把 session_key.openid 等字段作为用户的标识或者 session

  • 微信小程序获取用户openId的实现方法

    微信小程序获取用户openId的实现方法 前端: wx.login({ success: function (res) { res.code }) 获取到code后,传到后台, 然后请求微信接口 https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code 把参数替换为自己的参数,这个接口就直接返回openId了

  • 微信小程序获取用户信息的两种方法wx.getUserInfo与open-data实例分析

    本文实例讲述了微信小程序获取用户信息的两种方法wx.getUserInfo与open-data.分享给大家供大家参考,具体如下: 在此之前,小程序获取微信的头像,昵称之类的用户信息,我用的都是wx.getUserInfo,例如: onLoad: function (options) { var that = this; //获取用户信息 wx.getUserInfo({ success: function (res) { console.log(res); that.data.userInfo

  • 微信小程序获取用户信息及手机号(后端TP5.0)

    本文实例为大家分享了微信小程序获取用户信息及手机号的具体代码,供大家参考,具体内容如下 wxml页面 <view wx:if="{{config.tipsshow1}}" class='dialog-container'> <view class='dialog-mask'></view> <view class='dialog-info'> <view class='dialog-title'>login prompt<

  • 微信小程序获取用户手机号码的详细步骤

    目录 前言 接下来我们通过服务器获取授权 deciphering解密方法 总结 前言 我们在做小程序开发的过程中,经常会涉及到用户身份的问题,最普遍的就是我们要获取用户的手机号码,通过微信获取手机号码后可以减少很多操作,比如用户手机号码验证等,我们还可以给用户发送提示短信,那么本文主要讲解如何获取用户手机号码. 获取用户手机号码 分为以下几步: 第一点击页面获取授权按钮 第二获取用户授权参数 第三根据加解密算法解密手机号码 接下来我们来实现以上三步 先看前端页面 <!--index.wxml--

  • 微信小程序获取用户openid的方法详解

    目录 获取openid的思路 需要修改的地方 完整代码 总结 小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系 然而因为小程序中的openid不可以直接使用需要用code(登录凭证)去换取openid 获取openid的思路 获取openid首先需要调用小程序的login方法获取小程序的登录凭证code,然后使用code向微信换取登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session_key) 我这里是用一个点击事件来触

随机推荐