小程序最近发布了新功能,转发到群中的页面,再点击的时候可以获取群信息,比如群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 }解密结果转载请注明出处。