作者:小曾 | 来源:互联网 | 2023-09-25 10:28
最近项目移动端需要实现微信自定义分享功能,包含分享自定义标题、描述等。首先到公众号的后台,功能设置里面,添加将要被分享的域名,如图 后端签名算法实现,参考腾讯开发者文档https
最近项目移动端需要实现微信自定义分享功能,包含分享自定义标题、描述等。
- 首先到公众号的后台,功能设置里面,添加将要被分享的域名,如图
![.netcore2.1 JS-SDK 从后台获取微信签名,实现自定义分享标题、描述、图片 .netcore2.1 JS-SDK 从后台获取微信签名,实现自定义分享标题、描述、图片](https://img1.php1.cn/3cd4a/24d65/882/b20f7cbc5180a335.jpeg)
- 后端签名算法实现 ,参考腾讯开发者文档https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
jsapi_ticket
生成签名之前必须先了解一下jsapi_ticket,jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。由于获取jsapi_ticket的api调用次数非常有限,频繁刷新jsapi_ticket会导致api调用受限,影响自身业务,开发者必须在自己的服务全局缓存jsapi_ticket 。
生成签名步骤,获取AccessToken-》获取JsApiTicket-》生成签名
appsettings配置文件添加配置
"Api": {
"JSJDKBaseApi": "https://api.weixin.qq.com/cgi-bin"
},
"JSJDK": {
"AppId": "***",
"Secret": "****"
}
public class JSSDKSignHelper
{
private static AccessTokenResponse singleAccessToken;
private string _tencentApi { get; set; }
private string _appid { get; set; }
private string _appSecret { get; set; }
public JSSDKSignHelper(IConfiguration config)
{
_tencentApi = config["Api:JSJDKBaseApi"];
_appid = config["JSJDK:AppId"];
_appSecret = config["JSJDK:Secret"];
}
public string GetAccessTokenSingle(out bool isNewObj)
{
isNewObj = false;
if (singleAccessToken != null && (singleAccessToken.expire_out > DateTime.Now.AddHours(2)))
{
return singleAccessToken.access_token;
}
else
{
var respOnse= GetAccessToken();
if (response.errcode == 0)
{
response.expire_out = DateTime.Now.AddHours(expireHour);
singleAccessToken = response;
isNewObj = true;
return response?.access_token;
}
}
return null;
}
///
/// 获取access_token
///
///
private AccessTokenResponse GetAccessToken()
{
string url = _tencentApi + "/token?grant_type=client_credential&appid=" + _appid + "&secret=" + _appSecret;
var respOnse= ApiClient.GetJson(url);
return response;
}
///
/// 获取JsApiTicket
///
///
///
public string GetJsApiTicket(string accessToken)
{
if (string.IsNullOrWhiteSpace(accessToken))
{
return null;
}
string url = _tencentApi + $"/ticket/getticket?type=jsapi&access_token={accessToken}";
var respOnse= ApiClient.GetJson(url);
return response?.ticket;
}
///
/// 获取签名
///
///
/// 随机字符串(必须与wx.config中的nonceStr相同)
/// 时间戳(必须与wx.config中的timestamp相同)
/// 当前网页的URL,不包含#及其后面部分(必须是调用JS接口页面的完整URL)
///
public string GetSignature(string jsapi_ticket, string noncestr, string timestamp, string url)
{
if (string.IsNullOrEmpty(jsapi_ticket) || string.IsNullOrEmpty(noncestr) || string.IsNullOrEmpty(timestamp) || string.IsNullOrEmpty(url))
return null;
var string1Builder = new StringBuilder();
string1Builder.Append("jsapi_ticket=").Append(jsapi_ticket).Append("&")
.Append("nOncestr=").Append(noncestr).Append("&")
.Append("timestamp=").Append(timestamp).Append("&")
.Append("url=").Append(url.IndexOf("#") >= 0 ? url.Substring(0, url.IndexOf("#")) : url);
return Sha1Sign(string1Builder.ToString());
}
///
/// Sha1加密签名
///
///
///
public string Sha1Sign(string str)
{
SHA1 sha1 = new SHA1CryptoServiceProvider();
byte[] bytes_sha1_in = System.Text.UTF8Encoding.Default.GetBytes(str);
byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in);
string signature = BitConverter.ToString(bytes_sha1_out);
signature = signature.Replace("-", "").ToLower();
return signature;
}
}
public class AccessTokenResponse: BaseResponse
{
///
/// 返回access_token值,有效期7200秒
///
public string access_token { get; set; }
///
/// 过期时间,单位小时
///
public DateTime expire_out { get; set; }
}
public class AccessTicketResponse : BaseResponse
{
///
/// 返回Ticket票据,有效期7200秒
///
public string ticket { get; set; }
}
public class BaseResponse
{
///
/// 过期时间,单位秒
///
public string expire_in { get; set; }
///
/// 错误代码
///
public Int32 errcode { get; set; }
///
/// 错误信息描述
///
public string errmsg { get; set; }
}
///
/// 获取微信JS-JDK时间戳
///
///
public static string GetTimeStamp()
{
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
///
/// JS-JDK 创建随机字符串
///
///
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();
}
[HttpPost]
[Route("GetSignature")]
public string GetSignature(string url= "http://www.sina.cn/")
{
try
{
if (string.IsNullOrEmpty(url)) return "url不能为空";
string _jsTicket = null, _signature = null;
string _accessToken = _jsSignHelper.GetAccessTokenSingle(out bool isNewObj);
WxConfigModel model = new WxConfigModel();
model.AppId = appId;
model.TimeStamp = MyUtil.GetTimeStamp();
model.NonceStr = MyUtil.CreatenNonce_str();
if (isNewObj|| _wxConfigModel.Signature==null)
{
_jsTicket = _jsSignHelper.GetJsApiTicket(_accessToken);
_signature = _jsSignHelper.GetSignature(_jsTicket, model.NonceStr, model.TimeStamp, url);
model.jsTicket = _jsTicket;
model.Signature = _signature;
_wxConfigModel = model;
}
return JsonConvert.SerializeObject(model);
}
catch (Exception ex)
{
throw ex;
}
}
注意:
- 签名用的noncestr和timestamp必须与wx.config中的nonceStr和timestamp相同。
- 移动端分享时,不能本地测试,需要发布到外网测试,否则报签名错误
![.netcore2.1 JS-SDK 从后台获取微信签名,实现自定义分享标题、描述、图片 .netcore2.1 JS-SDK 从后台获取微信签名,实现自定义分享标题、描述、图片](https://img1.php1.cn/3cd4a/24d65/882/54217a5a74e6b7cc.jpeg)
- 生成的签名,可以实用校验工具校验是否正确。https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign