说明:

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. intllij IDE 中git ignore 无法删除target目录下的文件

    原因: git的本地忽略设置必须保证git的远程仓库分支上没有这个要忽略的文件,如果远程分支上存在这个文件,本地在设置ignore 这个文件,将会失败,无法commit忽略.(有人说是git的bug, ...

  2. leetcode394

    class Solution { public: string decodeString(string s) { stack<string> chars; stack<int> ...

  3. CentOS7(64)环境使用rpm命令安装gcc

    第一步:下载gcc相关的安装文件下载地址:http://vault.centos.org/7.0.1406/os/x86_64/Packages/ 下载以下文件: cpp-4.8.2-16.el7.x ...

  4. 25.Hibernate-配置文件.md

    目录 1.主配置文件 1.1定义 1.1.1分类 1.1.2分类 1.1.3不使用配置文件生成表 1.2教程 2. 映射配置文件 1.主配置文件 1.1定义 1.1.1分类 在hibernate的配置 ...

  5. prim及其练习

    关于prim,其实我今天才学... prim其实就是最小生成树的一种算法,严格每次的找最小边连到树上.看书上的代码看不懂,于是就自己大胆用堆优化写prim. 搞了很长时间,经过不写努力,还是搞出来了. ...

  6. Django项目vue前端依赖框架过大,工程打开太卡的问题

    前景提要:利用vue开发项目,由于依赖框架太大,导致pyCharm内存不够,项目打开太慢.步骤一:修改pyCharm的占用内存大小,按照下图操作.1.在应用程序中找到pyCharm,点击"显 ...

  7. Pushlet实现后台信息推送(一)

    Pushlet是使用较多的后台向前台推送信息的工具.前台订阅某个感兴趣的事件joinListen,触发后台的Pushlet的servlet,为该请求会话建立session,默认这个sessionID是 ...

  8. Android 二维码扫描/生成

    先看看实现效果 1.在module的build.gradle中执行compile操作 compile 'cn.yipianfengye.android:zxing-library:2.2' 2.在Ap ...

  9. MAC book 无法删除普通用户的解决办法

    1来自苹果官网 macOS Sierra: 删除用户或群组 如果您是管理员,当您不想再让某些用户访问 Mac 时,可以删除他们.您也可以删除不想要的群组. 删除用户时,您可以存储该用户的个人文件夹(包 ...

  10. 【网络编程】time_wait状态产生的原因,危害,如何避免

    转自:https://blog.csdn.net/u013616945/article/details/77510925  做略微修改  仅供个人学习 1. time_wait状态如何产生? 在tcp ...