小程序最近發布了新功能,轉發到群中的頁面,再點擊的時候可以獲取群信息,比如群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 }解密結果
轉載請注明出處。