小程序开发系列(六)获取群信息

小程序最近发布了新功能,转发到群中的页面,再点击的时候可以获取群信息,比如群ID,那要如何实现呢?

1.在页面中开启“转发”功能

代码如下

 onLoad: function () {
    wx.showShareMenu({
      withShareTicket: true
    });
  },

2.在页面中设置“转发”参数

 //转发
  onShareAppMessage: function () {
    return {
      title: '转发XXXX',
      path: '/pages/retrospect/retrospect',
      success: function (res) {
        // 转发成功
        var shareTickets = res.shareTickets;
        var shareTicket = shareTickets;
        wx.getShareInfo({
          shareTicket: shareTicket,
          success: function (res) {
            console.log('success');
            console.log(res);
            //console.log(res);
            wx.showToast({
              title: '转发成功',
              duration: 5000
            })
          },
          fail: function (res) {
            console.log('fail');
            console.log(res);
            wx.showToast({
              title: 'fail:' + res.errMsg,
              duration: 5000
            })
          }
        });
      },
      fail: function (res) {
        // 转发失败
      }
    }
  }
注:在转发的时候可以获取到shareTicket,使用shareTicket调用wx.getShareInfo可以得到群信息,具体实现请参看后面的代码。

3.响应用户从转发的群中进入

app.js的onLaunch在小程序启动时会触发一次,且直到小程序销毁。app.js中的onShow在小程序显示的时候会触发,只要显示就触发,所以会触发多次。在onLaunch和onShow函数中的参数options可以拿到shareTicket,具体要如何触发需要结合自身场景,简单的示例代码如下,

App({
  onLaunch: function (options) {
    //this.checkLogin(options.shareTicket);
    this.globalData.shareInfo=null;
  },
  onShow: function (options) {
    this.checkLogin(options.shareTicket);
  },
  checkLogin: function (shareTicket) {
    var that = this;
    wx.checkSession({
      success: function () {
        if (!that.globalData.session) {
          that.login(shareTicket);
        };
      },
      fail: function () {
        that.login(shareTicket);
      }
    })
  },
  //登录
  login: function (shareTicket) {
    var that = this
    wx.login({
      success: function (r) {
        if (r.code) {
          that.decodeSession(r.code, shareTicket);
        }
        wx.getUserInfo({
          success: function (res) {
            that.globalData.userInfo = res.userInfo;
          }
        })
      }
    })
  },
  //解密session信息
  decodeSession: function (code, shareTicket) {
    var that = this;
    wx.request({
      url: urls.WeiXin.FetchSessionInfo,//向后端发起换取session_key请求的URL
      data: {
        code: code
      },
      success: function (re) {
        if (re.data.Status == 0) {
          that.globalData.session = {
            openid: re.data.Data.openid,
            key: re.data.Data.session_key
          };
          if (shareTicket) {
            that.getShareInfo(shareTicket);
          }
        }
        else {
          that.globalData.session = null;
        }
      }
    })
  },
  //获取群信息
  getShareInfo: function (shareTicket) {
    var that = this;
    wx.getShareInfo({
      shareTicket: shareTicket,
      success: function (res) {
        wx.request({
          url: urls.WeiXin.Encrypt,//向后端发起解密请求的URL
          data: {
            encryptData: res.encryptedData,
            encryptSessionKey: that.globalData.session.key,
            iv: res.iv
          },
          success: function (re) {
            var msg='';
            if (re.data.Status == 0) {
              that.globalData.shareInfo =JSON.parse(re.data.Data);
              msg = '来自群转发';
            }
            else {
              that.globalData.session = null;
              msg=re.data.Message;
            }
            wx.showToast({
              title: msg,
              duration: 5000
            })
          }
        })        
      },
      fail: function (res) {
        console.log('fail');
        console.log(res.errMsg);
        wx.showToast({
          title: 'fail:' + res.errMsg,
          duration: 5000
        })
      }
    });
  },
  globalData: {
    userInfo: null,
    session: null,
    shareInfo: null
  }
})
注:

(1).必须要在执行wx.login登录后才能拿到群信息,否则getShareInfo会提示"you need login".

(2).登录得到的code拿到后端去换取session_key和openId,后面换取的数据是加密的需要进行解密才能得到session_key和openId.

(3).getShareInfo拿到的数据是加密的数据,需要传到后端去解密,解密时需要encryptData、session_key和iv。其中encryptData和iv在getShareInfo的res中可以拿到,session_key在登录的时候可以换取得到。

4.换取session_key

后端使用asp.net的MVC中的C层,即控制器来处理。具体可以参看网络中的相关文章。

session控制器的代码如下

 /// <summary>
    /// 微信会话
    /// </summary>
    public class WXSessionController : ApiController
    {
        #region FetchSessionInfo
        /// <summary>
        /// 获取SESSION信息
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public BaseDataPackage<WXSessionInfoPackage> FetchSessionInfo(string code)
        {
            var result = new BaseDataPackage<WXSessionInfoPackage>();
            var data = WXSession.FetchSessionInfo(code);
            result.Data = data;
            if (data != null && data.IsOK())
            {
                result.Status = StatusCode.OK;
                result.Message = "OK";
            }
            else
            {
                result.Status = StatusCode.FAIL;
                result.Message = data.errmsg;
            }
            return result;
        }
        #endregion
    }
 public class BaseDataPackage<T>
    {
        public BaseDataPackage();

        public int Status { get; set; }
        public string Message { get; set; }
        public T Data { get; set; }

        public bool IsOK(){return Status==0;}
    }
//
    // 摘要:
    //     WebApi请求的状态码
    public class StatusCode
    {
        //
        // 摘要:
        //     请求成功
        public const int OK = 0;
        //
        // 摘要:
        //     失败
        public const int FAIL = 1;
        //
        // 摘要:
        //     异常
        public const int EXCEPTION = 2;
}
 public class WXSessionInfoPackage : WXPackageBase
    {
        public string openid { get; set; }

        public string session_key { get; set; }
    }
    public class WXPackageBase
    {
        #region 属性
        public int errcode { get; set; } = StatusCode.OK;

        public string errmsg { get; set; }
        #endregion

        #region IsOK
        public bool IsOK()
        {
            if (errcode == StatusCode.OK)
            {
                return true;
            }

            return false;
        }
        #endregion
    }

  public class WXSession
    {
/// <summary>
        /// code 换取 session_key、openid
        /// </summary>
        public const string SNS_JSCODE2SESSION = "https://api.weixin.qq.com/sns/jscode2session?appid={0}&secret={1}&js_code={2}&grant_type=authorization_code";

        #region FetchSessionInfo
        public static WXSessionInfoPackage FetchSessionInfo(string code)
        {
	    //AppId和AppSecret从微信的小程序页面中复制下来即可
            string url = string.Format(SNS_JSCODE2SESSION,AppId, AppSecret, code);
            var sessionInfo = HttpHelper.Get<WXSessionInfoPackage>(url);
            if (sessionInfo != null)
            {
                sessionInfo.session_key = Encrypt(sessionInfo.session_key);
                sessionInfo.openid = Encrypt(sessionInfo.openid);
            }
            return sessionInfo;
        }
        #endregion

        #region Encrypt
        /// <summary>
        /// 对session的数据加密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string Encrypt(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                return data;
            }
            var buff = Encoding.UTF8.GetBytes(data);
            var dest = Convert.ToBase64String(buff);
            return dest;
        }
        #endregion

        #region Descrypt
        /// <summary>
        /// 对session的数据解密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static string Descrypt(string data)
        {
            if (string.IsNullOrEmpty(data))
            {
                return data;
            }
            var buff = Convert.FromBase64String(data);
            var dest = Encoding.UTF8.GetString(buff);
            return dest;
        }
        #endregion
    }



注:为了数据的安全,获取到的session_key和openid作了加密处理,即Encrypt方法,Encrypt的实现依需要而不同,比如可以使用简单的base64加密等。为此需要有一个对应的解密方法Decrypt.

附HttpHelper.Get方法

 /// <summary>
    /// HTTP帮助类
    /// </summary>
    public class HttpHelper
    {
        #region Get
        /// <summary>
        /// 执行基本的命令方法,以Get方式
        /// </summary>
        /// <param name="apiurl">请求的URL</param>
        /// <param name="headers">请求头的key-value字典</param>
        /// <param name="needReturnHeader">true:返回响应头,数据将以{Header:headerDict,Data:responseStr}的json格式返回,
        /// 其中headerDict为响应头的字典格式的数据,responseStr为请求返回的响应字符串.false:直接返回响应数据</param>
        /// <returns></returns>
        public static string Get(string apiurl, Dictionary<string, string> headers = null, bool needReturnHeader = false)
        {
            WebRequest request = WebRequest.Create(apiurl);
            request.Method = RequestMethod.GET;
            if (headers != null)
            {
                foreach (var keyValue in headers)
                {
                    request.Headers.Add(keyValue.Key, keyValue.Value);
                }
            }
            WebResponse response = request.GetResponse();
            Stream stream = response.GetResponseStream();
            Encoding encode = Encoding.UTF8;
            StreamReader reader = new StreamReader(stream, encode);
            string resultJson = reader.ReadToEnd();
            if (needReturnHeader)
            {
                Dictionary<string, string> headerDict = new Dictionary<string, string>();
                foreach (var key in response.Headers.AllKeys)
                {
                    headerDict.Add(key, response.Headers[key]);
                }
                var temp = new
                {
                    Header = headerDict,
                    Data = resultJson
                };
                return temp.ToJson();
            }
            else
            {
                return resultJson;
            }
        }
#endregion
}
微信开发工具拿到的session_key


5.解密群信息

   public class WXEncrypt
    {
        #region Decrypt
        /// <summary>
        /// 解密数据
        /// </summary>
        /// <param name="encryptStrOfBase64">base64加密后的字符串,如果没有进行URL编码直接传输,加号在传输时会变成空格,
此时建议替换成%2B传输.wx.request会默认进行URL编码。</param>
        /// <param name="encryptSessionKey">加密后的sessionKey</param>
        /// <param name="iv"></param>
        /// <returns></returns>
        public static string Decrypt(string encryptStrOfBase64, string encryptSessionKey, string iv)
        {
            var sessionKey = WXSession.Descrypt(encryptSessionKey);
            encryptStrOfBase64 = encryptStrOfBase64.Replace("%2B", "+");
            if (sessionKey.Length % 3 == 1)
            {
                sessionKey += "==";
            }
            else if (sessionKey.Length % 3 == 2)
            {
                sessionKey += "=";
            }
            var Key = Convert.FromBase64String(sessionKey);
            var Iv = Convert.FromBase64String(iv);
            byte[] dataByte = AesEncryptHelper.Decrypt(encryptStrOfBase64, Iv, Key);
            string dataStr = Encoding.UTF8.GetString(dataByte);
            return dataStr;
        }
        #endregion

   /// <summary>
    /// AES算法
    /// </summary>
    public class AesEncryptHelper
    {
        #region Decrypt
        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="encryptStrOfBase64"></param>
        /// <param name="Iv"></param>
        /// <param name="Key"></param>
        /// <returns></returns>
        public static byte[] Decrypt(String encryptStrOfBase64, byte[] Iv, byte[] Key)
        {
            RijndaelManaged aes = new RijndaelManaged();
            aes.KeySize = 256;
            aes.BlockSize = 128;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.None;
            aes.Key = Key;
            aes.IV = Iv;
            var decrypt = aes.CreateDecryptor(aes.Key, aes.IV);
            byte[] xBuff = null;
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, decrypt, CryptoStreamMode.Write))
                {
                    byte[] xXml = Convert.FromBase64String(encryptStrOfBase64);
                    byte[] msg = new byte[xXml.Length + 32 - xXml.Length % 32];
                    Array.Copy(xXml, msg, xXml.Length);
                    cs.Write(xXml, 0, xXml.Length);
                }
                xBuff = decode(ms.ToArray());
            }
            return xBuff;
        }


        #region decode
        private static byte[] decode(byte[] decrypted)
        {
            int pad = (int)decrypted[decrypted.Length - 1];
            if (pad < 1 || pad > 32)
            {
                pad = 0;
            }
            byte[] res = new byte[decrypted.Length - pad];
            Array.Copy(decrypted, 0, res, 0, decrypted.Length - pad);
            return res;
        }
        #endregion

        #endregion
}
解密结果

转载请注明出处。






原文地址:https://www.cnblogs.com/sparkleDai/p/7604889.html