说明:

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 = ; i < ; i++)
{
sb.Append(strs[r.Next(length - )]);
}
return sb.ToString();
} /// <summary>
/// 获取时间戳
/// </summary>
/// <returns></returns>
public static long CreatenTimestamp()
{
return (DateTime.Now.ToUniversalTime().Ticks - ) / ;
} /// <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('#')[];

$.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; }
}
}

H5+.Net Webapi集成微信分享前后端代码 微信JS-SDK wx.onMenuShareTimeline wx.onMenuShareAppMessage的更多相关文章

  1. 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.0.0版)

    TableGo v6.0.0 版震撼发布,此次版本更新如下: 1.UI界面大改版,组件大调整,提升界面功能的可扩展性. 2.新增BeautyEye主题,界面更加清新美观,也可以通过配置切换到原生Jav ...

  2. [Java 开源项目]一款无需写任何代码,即可一键生成前后端代码的工具

    作者:HelloGitHub-小鱼干 JeecgBoot 是一款基于代码生成器的低代码开发平台,零代码开发.JeecgBoot 采用开发模式:Online Coding 模式-> 代码生成器模式 ...

  3. 记node前后端代码共用的一次坑

    项目背景 nodejs项目,webpack打包,用axios请求,Promise封装,nunjucks模板引擎: 之前已将nunjucks模板通过webpack打包策略,做成前后端共用: 目前需要将网 ...

  4. 实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了

    实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了 前言 在日常的软件开发中,程序员往往需要花费大量的时间写CRUD,不仅枯燥效率低,而且每个人的代码风格不统一.MyBatis-P ...

  5. 【SpringSecurity系列3】基于Spring Webflux集成SpringSecurity实现前后端分离无状态Rest API的权限控制

    源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/02-springsecurity-state ...

  6. 微信分享自定义图片标题摘要-微信官方API

    我们平时在使用微信内置浏览器打开网页想要分享给好友或者发到朋友圈的时候经常会遇到这样的问题, 别人的网页分享的时候是这样的: 而我们自己的网页分享后这这样的: 看到有人说不做任何设置,微信分享时会自动 ...

  7. 封装微信分享到朋友/朋友圈js

    在页面引入: <script src="/static/lib/jquery-2.2.2.min.js"></script><script src=& ...

  8. layui上传文件组件(前后端代码实现)

    我个人博客系统上传特色图片功能就是用layui上传文件组件做的.另外采用某个生态框架,尽量都统一用该生态框架对应的解决方案,因为这样一来,有这么几个好处?1.统一而不杂糅,有利于制定相应的编码规范,方 ...

  9. SpringCloud微服务实战——搭建企业级开发框架(三十一):自定义MybatisPlus代码生成器实现前后端代码自动生成

      理想的情况下,代码生成可以节省很多重复且没有技术含量的工作量,并且代码生成可以按照统一的代码规范和格式来生成代码,给日常的代码开发提供很大的帮助.但是,代码生成也有其局限性,当牵涉到复杂的业务逻辑 ...

随机推荐

  1. orcal 安装失败解决办法

    若安装失败

  2. powerdesigner 基本概念

    PowerDesigner是Sybase的企业建模和设计解决方案,采用模型驱动方法,将业务与IT结合起来,可帮助部署有效的企业体系架构,并为研发生命周期管理提供强大的分析与设计技术.PowerDesi ...

  3. filter in Servlet

    Servlet过滤器: Servlet过滤器是用于执行某些过滤任务的对象.过滤器可以应用于servlet,jsp或html. Servlet过滤器主要用于以下任务: 预处理: Servlet过滤器用于 ...

  4. Jmeter正则表达式提取器(转载)

    转载自 http://blog.csdn.net/qq_35885203 使用jmeter来测试时,经常会碰到需要上下文传输数据的情况,如登录后生成的token,在其他页面的操作,都需传入这个toke ...

  5. PL2303 USB转串口 com

    PL2303 USB转串口 com PL-2303 XA/HXA chip http://www.prolific.com.tw/US/ShowProduct.aspx?p_id=225&pc ...

  6. Beta冲刺——第三天

    beta冲刺:第三天 各个成员今日完成的任务 成员 冯晓.马思远 彭辉.王爽 吴琼.郝延婷 今日完成任务 ·管理员管理功能模块下角色管理功能的完善测试 ·角色和权限部分代码规范 ·博客撰写 ·后台系统 ...

  7. Beta冲刺——第四天

    beat冲刺:第四天 各个成员今日完成的任务 成员 冯晓.马思远 彭辉.王爽 吴琼.郝延婷 今日完成任务 ·管理员功能模块的代码规范与测试 ·后台审稿系统代码规范 ·代码规范 ·系统审稿模块功能测试 ...

  8. [转]jquery.form.js的ajaxSubmit和ajaxForm使用

    参考 http://www.cnblogs.com/popzhou/p/4338040.html 依赖的脚本文件 <script src="../Javascript/jquery-1 ...

  9. JS 操作样式 style

    1. 任何支持 style 特性的 HTML 元素在 JavaScript 中都对应着有一个 style 属性,指向一个 CSSStyleDeclaration 的一个实例对象,包含该元素的内嵌sty ...

  10. TaskScheduler

    一初始化 在SparkContext初始化的时候,同时初始化三个对象.DAGScheduler,TaskScheduler,SchedulerBackend.DAGScheduler,前面已经讲到,做 ...