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 = ; 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}×tamp={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的更多相关文章
- 基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.0.0版)
TableGo v6.0.0 版震撼发布,此次版本更新如下: 1.UI界面大改版,组件大调整,提升界面功能的可扩展性. 2.新增BeautyEye主题,界面更加清新美观,也可以通过配置切换到原生Jav ...
- [Java 开源项目]一款无需写任何代码,即可一键生成前后端代码的工具
作者:HelloGitHub-小鱼干 JeecgBoot 是一款基于代码生成器的低代码开发平台,零代码开发.JeecgBoot 采用开发模式:Online Coding 模式-> 代码生成器模式 ...
- 记node前后端代码共用的一次坑
项目背景 nodejs项目,webpack打包,用axios请求,Promise封装,nunjucks模板引擎: 之前已将nunjucks模板通过webpack打包策略,做成前后端共用: 目前需要将网 ...
- 实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了
实战:一键生成前后端代码,Mybatis-Plus代码生成器让我舒服了 前言 在日常的软件开发中,程序员往往需要花费大量的时间写CRUD,不仅枯燥效率低,而且每个人的代码风格不统一.MyBatis-P ...
- 【SpringSecurity系列3】基于Spring Webflux集成SpringSecurity实现前后端分离无状态Rest API的权限控制
源码传送门: https://github.com/ningzuoxin/zxning-springsecurity-demos/tree/master/02-springsecurity-state ...
- 微信分享自定义图片标题摘要-微信官方API
我们平时在使用微信内置浏览器打开网页想要分享给好友或者发到朋友圈的时候经常会遇到这样的问题, 别人的网页分享的时候是这样的: 而我们自己的网页分享后这这样的: 看到有人说不做任何设置,微信分享时会自动 ...
- 封装微信分享到朋友/朋友圈js
在页面引入: <script src="/static/lib/jquery-2.2.2.min.js"></script><script src=& ...
- layui上传文件组件(前后端代码实现)
我个人博客系统上传特色图片功能就是用layui上传文件组件做的.另外采用某个生态框架,尽量都统一用该生态框架对应的解决方案,因为这样一来,有这么几个好处?1.统一而不杂糅,有利于制定相应的编码规范,方 ...
- SpringCloud微服务实战——搭建企业级开发框架(三十一):自定义MybatisPlus代码生成器实现前后端代码自动生成
理想的情况下,代码生成可以节省很多重复且没有技术含量的工作量,并且代码生成可以按照统一的代码规范和格式来生成代码,给日常的代码开发提供很大的帮助.但是,代码生成也有其局限性,当牵涉到复杂的业务逻辑 ...
随机推荐
- Mac ssh 免密码登录 Mac 或者 Linux
最近在 Mac上操作另一台 Mac 和 Linux 服务器,每次输密码太麻烦.所以直接设置 ssh 免密码登录,省去输入密码的过程.先在本机执行 ls ~/.ssh 若不存在 id_rsa,id_rs ...
- 关于ie6块元素行内元素转换
1.inline元素的display属性设置为inline-block时,所有的浏览器都支持: 2.block元素的display属性设置为inline-block时,IE6/IE7浏览器是不支持的: ...
- web.xml hello1代码分析
在“Web页”节点下,展开WEB-INF节点,然后双击web.xml文件进行查看. 上下文参数提供Web应用程序所需的配置信息.应用程序可以定义自己的上下文参数.此外,JavaServer Faces ...
- 如何利用sql 读取辅表的最大max 和第二最大max。。。。
SELECT `主表`.id, `主表`.title, `辅表`.* FROM tableB AS `辅表` INNER JOIN tableA AS `主表` ON `主表`.id = `辅表`.f ...
- Spring MVC 自动为对象注入枚举类型
原文地址:http://1358440610-qq-com.iteye.com/blog/2079048 如果一个对象里面有枚举类型的话,则Spring MVC是不能够直接进行注入的,因为它只实现了一 ...
- php-beanstalkd消息队列类分享
<?php namespace Common\Business; /** * beanstalk: A minimalistic PHP beanstalk client. * * Copyri ...
- 34 【kubernetes】安装手册
全文参考了两篇中文文档: 1,https://www.cnblogs.com/RainingNight/p/using-kubeadm-to-create-a-cluster.html 2,http: ...
- stark组件开发之关键搜索
- 模糊搜索: 在页面生成一个表单. 以get 方式, 将数据提交到.当前查看页面. 后台接收数据,然后进行筛选过滤. 着个也需要,用户自定制! 定义一个 search_list 这个值,默 ...
- 原生JS实现图片预览功能
html代码: <div class="album-new fr"> <div class="upload-btn btn-new container& ...
- 2018php最新面试题之PHP核心技术
一.PHP核心技术 1.写出一个能创建多级目录的PHP函数(新浪网技术部) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php ...