• 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.TotalSeconds < 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.TotalSeconds < expiresIn)
                        return accessToken;
                }
                return string.Empty;
    
            }
        }
    }

    三 JS部分

    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; }
        }
    }
  • 相关阅读:
    SpringBoot全局日志管理(AOP)
    SpringBoot集成Shiro
    MybatisPlus使用介绍
    SpringBoot集成MybatisPlus
    SpringBoot集成多数据源
    SpringBoot事务管理
    ETL 工具和 BI 工具
    oracle中行转列操作
    Oracle基本数据类型总结
    LINUX中lrzsz软件的使用
  • 原文地址:https://www.cnblogs.com/eedc/p/9521297.html
Copyright © 2020-2023  润新知