H5+.Net Webapi集成微信分享前后端代码 微信JS-SDK wx.onMenuShareTimeline wx.onMenuShareAppMessage

说明:

1/因为赚麻烦这里没有使用数据库或服务器缓存来存储access_token和jsapi_ticket,为了方便这里使用了本地的xml进行持久化这两个值以及这两个值的创建时间和有限期限。

2/每次请求先检查有没有存在并且在有效期内的access_token和jsapi_ticket,存在的话直接进行加密操作,不存在或过期重新请求wechat接口获得再进行加密。

3/每个分享的页面都需要将当页的url发送到服务器进行签名,且一定要encodeURIComponent,因为在微信中打开会自动给当前链接加个各种参数,从而导致url不一致,导致invalid signature签名错误。

4/分享的图标url( imgUrl )必须是绝对路径。

 

一 封装的微信授权工具类

WechatJsSdk.cs

using SouthRuiHeH5.Models;using System;using System.IO;using System.Linq;using System.Net;using System.Security.Cryptography;using System.Text;using System.Web.Script.Serialization;using System.Xml.Linq;namespace SouthRuiHeH5.Provider{ public class WechatJsSdk { /// <summary> /// 模拟get请求获取AccessToken /// </summary> /// <param name="appID"></param> /// <param name="appSecret"></param> /// <returns></returns> public static string GetAccessToken(string appID, string appSecret) { string url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appID, appSecret); JavaScriptSerializer js = new JavaScriptSerializer(); AccessTokenOutput output = js.Deserialize<AccessTokenOutput>(HttpGet(url)); SaveAccessTokenInXml(output); return output.access_token; } /// <summary> /// 将AccessToken保存进xml /// </summary> /// <param name="input"></param> private static void SaveAccessTokenInXml(AccessTokenOutput input) { if (string.IsNullOrWhiteSpace(input?.access_token)) return; var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/"); string filePath = mappedPath + "Xml/AccessToken.xml"; XDocument inputDoc = XDocument.Load(filePath); inputDoc.Elements().First().Element("access_token").Value = input.access_token; inputDoc.Elements().First().Element("expires_in").Value = input.expires_in; inputDoc.Elements().First().Element("create_time").Value = DateTime.Now.ToString(); inputDoc.Save(filePath); } /// <summary> /// 模拟get请求获取JsapiTicket /// </summary> /// <param name="accessToken"></param> /// <returns></returns> public static string GetJsapiTicket(string accessToken) { string url = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi", accessToken); JavaScriptSerializer js = new JavaScriptSerializer(); JsapiTicketOutput output = js.Deserialize<JsapiTicketOutput>(HttpGet(url)); SaveJsapiTicketInXml(output); return output.ticket; } /// <summary> /// 将JsapiTicket保存进xml /// </summary> /// <param name="input"></param> private static void SaveJsapiTicketInXml(JsapiTicketOutput input) { if (string.IsNullOrWhiteSpace(input?.ticket)) return; var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/"); string filePath = mappedPath + "Xml/JsapiTicket.xml"; XDocument inputDoc = XDocument.Load(filePath); inputDoc.Elements().First().Element("ticket").Value = input.ticket; inputDoc.Elements().First().Element("expires_in").Value = input.expires_in; inputDoc.Elements().First().Element("create_time").Value = DateTime.Now.ToString(); inputDoc.Save(filePath); } /// <summary> /// get模拟请求 /// </summary> /// <param name="Url"></param> /// <param name="postDataStr"></param> /// <returns></returns> private static string HttpGet(string Url, string postDataStr = "") { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url + (postDataStr == "" ? "" : "?") + postDataStr); request.Method = "GET"; request.ContentType = "text/html;charset=UTF-8"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream myResponseStream = response.GetResponseStream(); StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8")); string retString = myStreamReader.ReadToEnd(); myStreamReader.Close(); myResponseStream.Close(); return retString; } private static string[] strs = new string[] { "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" }; /// <summary> /// 获取随机字符串 /// </summary> /// <returns></returns> public static string CreatenNonce_str() { Random r = new Random(); var sb = new StringBuilder(); var length = strs.Length; for (int i = 0; i < 15; i++) { sb.Append(strs[r.Next(length - 1)]); } return sb.ToString(); } /// <summary> /// 获取时间戳 /// </summary> /// <returns></returns> public static long CreatenTimestamp() { return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000; } /// <summary> /// sha1加密string1 获得Signature /// </summary> /// <param name="jsapi_ticket"></param> /// <param name="noncestr"></param> /// <param name="timestamp"></param> /// <param name="url"></param> /// <returns></returns> public static string GetSignature(string jsapi_ticket, string noncestr, long timestamp, string url) { string string1 = string.Format("jsapi_ticket={0}&noncestr={1}&timestamp={2}&url={3}", jsapi_ticket, noncestr, timestamp, url); return Sha1(string1); } /// <summary> /// sha1 /// </summary> /// <param name="orgStr"></param> /// <param name="encode"></param> /// <returns></returns> private static string Sha1(string orgStr, string encode = "UTF-8") { var sha1 = new SHA1Managed(); var sha1bytes = System.Text.Encoding.GetEncoding(encode).GetBytes(orgStr); byte[] resultHash = sha1.ComputeHash(sha1bytes); string sha1String = BitConverter.ToString(resultHash).ToLower(); sha1String = sha1String.Replace("-", ""); return sha1String; } }}

 

二  webapi部分

ConfigController.cs

using SouthRuiHeH5.Models;using SouthRuiHeH5.Provider;using System;using System.Configuration;using System.Linq;using System.Web.Http;using System.Xml.Linq;namespace SouthRuiHeH5.Controllers{ public class ConfigController : ApiController { public ConfigOutput Get([FromUri]string url) { string appId = ConfigurationManager.AppSettings.Get("AppId"); string appSecret = ConfigurationManager.AppSettings.Get("AppSecret"); if (string.IsNullOrWhiteSpace(appId)) throw new Exception("AppSeeting:AppId Missed"); if (string.IsNullOrWhiteSpace(appSecret)) throw new Exception("AppSeeting:AppSecret Missed"); string jsapiTicket = getJsapiTicketFromXml(); if (string.IsNullOrEmpty(jsapiTicket)) { string accessToken = GetAccessTokenFromXmlFirst(); if (string.IsNullOrEmpty(accessToken)) accessToken = WechatJsSdk.GetAccessToken(appId, appSecret); if (string.IsNullOrEmpty(accessToken)) throw new Exception("Get AccessToken Error"); jsapiTicket = WechatJsSdk.GetJsapiTicket(accessToken); if (string.IsNullOrEmpty(jsapiTicket)) throw new Exception("Get JsapiTicket Error"); } ConfigOutput output = new ConfigOutput { appId = appId, nonceStr = WechatJsSdk.CreatenNonce_str(), timestamp = WechatJsSdk.CreatenTimestamp() }; output.signature = WechatJsSdk.GetSignature(jsapiTicket, output.nonceStr, output.timestamp, url); return output; } /// <summary> /// 检查xml是否有JsapiTicket,并且JsapiTicket在有效期内 /// </summary> /// <returns></returns> private string getJsapiTicketFromXml() { var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/"); string filePath = mappedPath + "Xml/JsapiTicket.xml"; XDocument inputDoc = XDocument.Load(filePath); string ticket = inputDoc.Elements().First().Element("ticket").Value; bool expiresInTry = int.TryParse(inputDoc.Elements().First().Element("expires_in").Value, out int expiresIn); bool createTimeTry = DateTime.TryParse(inputDoc.Elements().First().Element("create_time").Value, out DateTime createTime); if (!string.IsNullOrWhiteSpace(ticket) || !expiresInTry || !createTimeTry) { TimeSpan timeSpan = DateTime.Now.Subtract(createTime); if (timeSpan.Seconds < expiresIn) return ticket; } return string.Empty; } /// <summary> /// 检查xml是否有AccessToken,并且AccessToken在有效期内 /// </summary> /// <returns></returns> private string GetAccessTokenFromXmlFirst() { var mappedPath = System.Web.Hosting.HostingEnvironment.MapPath("~/"); string filePath = mappedPath + "Xml/AccessToken.xml"; XDocument inputDoc = XDocument.Load(filePath); string accessToken = inputDoc.Elements().First().Element("access_token").Value; bool expiresInTry = int.TryParse(inputDoc.Elements().First().Element("expires_in").Value, out int expiresIn); bool createTimeTry = DateTime.TryParse(inputDoc.Elements().First().Element("create_time").Value, out DateTime createTime); if (!string.IsNullOrWhiteSpace(accessToken) || !expiresInTry || !createTimeTry) { TimeSpan timeSpan = DateTime.Now.Subtract(createTime); if (timeSpan.Seconds < expiresIn) return accessToken; } return string.Empty; } }}

 

三 JS部分

H5+.Net Webapi集成微信分享前后端代码 微信JS-SDK wx.onMenuShareTimeline wx.onMenuShareAppMessage

wechat.share.js

var url = window.location.href.split(#)[0];$.get("/api/Config?url=" + encodeURIComponent(url), function (res) { if (!res) return; var input = res; //input.debug = true; input.jsApiList = ["onMenuShareTimeline", "onMenuShareAppMessage"]; wx.config(input);});wx.ready(function () { onMenuShareTimeline(); onMenuShareAppMessage();});function onMenuShareTimeline() { wx.onMenuShareTimeline({ title: 为态度喝彩!, desc: 唯有创造价值,才能共享价值。南方瑞合三年定开基金(LOF)盛大发行中。, link: url, imgUrl: http://southruihe.huiz.cn/image/sharelogo.jpg, success: function () { } });}function onMenuShareAppMessage() { wx.onMenuShareAppMessage({ title: 为态度喝彩!, desc: 唯有创造价值,才能共享价值。南方瑞合三年定开基金(LOF)盛大发行中。, link: url, imgUrl: http://southruihe.huiz.cn/image/sharelogo.jpg, success: function () { } });}

 

四 其中使用的3个数据传输类

AccessTokenOutput.cs

namespace SouthRuiHeH5.Models{ public class AccessTokenOutput { public string access_token { get; set; } public string expires_in { get; set; } public string errcode { get; set; } public string errmsg { get; set; } }}

ConfigOutput.cs

namespace SouthRuiHeH5.Models{ public class ConfigOutput { /// <summary> /// 必填,公众号的唯一标识 /// </summary> public string appId { get; set; } /// <summary> /// 必填,生成签名的时间戳 /// </summary> public long timestamp { get; set; } /// <summary> /// 必填,生成签名的随机串 /// </summary> public string nonceStr { get; set; } /// <summary> /// 必填,签名 /// </summary> public string signature { get; set; } }}

JsapiTicketOutput.cs

namespace SouthRuiHeH5.Models{ public class JsapiTicketOutput { public string errcode { get; set; } public string errmsg { get; set; } public string ticket { get; set; } public string expires_in { get; set; } }}

 

相关文章