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