对于上面这些基本的东西就不在多说,下面我们重点看一下如何获取jsapi_ticket,如何进行签名。官方文档提示的步骤是,先获取access_token,然后通过access_token来获取jsapi_ticket,最后通过jsapi_ticket进行签名。下面我们就一步一步完成上面的工作。注:官方提供了php、java、python、nodejs的实例程序,这里我将以C#为例为大家结束如何完成上面的操作。
第一步、获取access_token
官方文档是这样说的:access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。
第二步获取jsapi_ticket
官方文档是这样说的:jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
1.参考以下文档获取access_token(有效期7200秒,开发者必须在自己的服务全局缓存access_token):../15/54ce45d8d30b6bf6758f68d2e95bc627.html
2.用第一步拿到的access_token 采用http GET方式请求获得jsapi_ticket(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
获得jsapi_ticket之后,就可以生成JS-SDK权限验证的签名了。
第三步生成JS-SDK权限验证的签名
签名生成规则如下:参与签名的字段包括noncestr(随机字符串), 有效的jsapi_ticket, timestamp(时间戳), url(当前网页的URL,不包含#及其后面部分) 。对所有待签名参数按照字段名的ASCII 码从小到大排序(字典序)后,使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串string1。这里需要注意的是所有参数名均为小写字符。对string1作sha1加密,字段名和字段值都采用原始值,不进行URL 转义。
注意事项
1.签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同;
2.签名用的url必须是调用JS接口页面的完整URL;
3.出于安全考虑,开发者必须在服务器端实现签名的逻辑。
以上便是微信JS SDK的签名逻辑部分,下面奉上具体的代码实现:
using System; using System.Net; using System.Web.Mvc; using System.IO; using System.Text; using System.Web.Script.Serialization; using ManYiAbyWAP.Models; /// <summary> /// 微信获取jsapi_ticket /// </summary> namespace ManYiAbyWAP.Controllers { public class WXMessageController : Controller { private static string APPID = "微信提供的appid"; private static string SECRECT = "微信提供的secrect"; public static WXInfo accessToken = null;//全局对象,每7200秒更新一次,微信对每日获取Token有请求次数与时效限制 public static DateTime overTime = DateTime.Now;//用于Token的过期验证 public ActionResult GetToken(string url) { if (accessToken != null) { TimeSpan span = Convert.ToDateTime(overTime).Subtract(Convert.ToDateTime(DateTime.Now)); if (span.TotalHours > 2) { accessToken = GETWinXinToken(); overTime = DateTime.Now; } } else { accessToken = GETWinXinToken(); overTime = DateTime.Now; } //生成签名的时间戳 TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); accessToken.timestamp = Convert.ToInt64(ts.TotalSeconds).ToString(); //获取随机串 accessToken.noncestr = createNonceStr(16); string str = "jsapi_ticket="+ accessToken .ticket+ "&noncestr="+ accessToken.noncestr + "×tamp="+ accessToken.timestamp + "&url="+ url; accessToken.signature = SHA1(str).ToLower(); accessToken.APPID = APPID; return Json(accessToken, JsonRequestBehavior.AllowGet); } //生成随机串 private string createNonceStr(int length = 16) { string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; Random r = new Random(); string result = string.Empty; //生成一个8位长的随机字符,具体长度可以自己更改 for (int i = 0; i < length; i++) { int m = r.Next(0, 62);//这里下界是0,随机数可以取到,上界应该是62,因为随机数取不到上界,也就是最大62,符合我们的题意 string s = str.Substring(m, 1); result += s; } return result; } //散列算法 private static string SHA1(string text) { byte[] cleanBytes = Encoding.Default.GetBytes(text); byte[] hashedBytes = System.Security.Cryptography.SHA1.Create().ComputeHash(cleanBytes); return BitConverter.ToString(hashedBytes).Replace("-", ""); } //通过GET请求获取Token private static WXInfo GETWinXinToken() { //获取access_token HttpWebResponse response = CreateGetHttpResponse("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECRECT, 5000); StreamReader reader = new StreamReader(response.GetResponseStream()); String line; StringBuilder sb = new StringBuilder(); while ((line = reader.ReadLine()) != null) { sb.Append(line.ToString()); } JavaScriptSerializer js = new JavaScriptSerializer(); WXInfo accessToken = js.Deserialize<WXInfo>(sb.ToString()); //获取jsapi_ticket response = CreateGetHttpResponse("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accessToken.access_token + "&type=jsapi", 5000); reader = new StreamReader(response.GetResponseStream()); sb = new StringBuilder(); while ((line = reader.ReadLine()) != null) { sb.Append(line.ToString()); } accessToken = js.Deserialize<WXInfo>(sb.ToString()); return accessToken; } /// <summary> /// 创建GET方式的HTTP请求 /// </summary> /// <param>请求的URL</param> /// <param>请求的超时时间</param> /// <param>请求的客户端浏览器信息,可以为空</param> /// <param>随同HTTP请求发送的Cookie信息,如果不需要身份验证可以为空</param> /// <returns></returns> public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent=null, CookieCollection cookies=null) { if (string.IsNullOrEmpty(url)) { throw new ArgumentNullException("url"); } HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; request.Method = "GET"; if (!string.IsNullOrEmpty(userAgent)) { request.UserAgent = userAgent; } if (timeout.HasValue) { request.Timeout = timeout.Value; } if (cookies != null) { request.CookieContainer = new CookieContainer(); request.CookieContainer.Add(cookies); } return request.GetResponse() as HttpWebResponse; } } }
用于存放Token信息的全局对象WXInfo.cs