欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.netcore2.1 JS-SDK 从后台获取微信签名,实现自定义分享标题、描述、图片

程序员文章站 2022-06-28 20:20:15
最近项目移动端需要实现微信自定义分享功能,包含分享自定义标题、描述等。 首先到公众号的后台,功能设置里面,添加将要被分享的域名,如图 后端签名算法实现 ,参考腾讯开发者文档https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp142114111 ......

  最近项目移动端需要实现微信自定义分享功能,包含分享自定义标题、描述等。

  • 首先到公众号的后台,功能设置里面,添加将要被分享的域名,如图

 

.netcore2.1  JS-SDK  从后台获取微信签名,实现自定义分享标题、描述、图片

 

  • 后端签名算法实现 ,参考腾讯开发者文档

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

        /// <summary>
        /// 获取access_token
        /// </summary>
        /// <returns></returns>
        private accesstokenresponse getaccesstoken()
        {
           
            string url = _tencentapi + "/token?grant_type=client_credential&appid=" + _appid + "&secret=" + _appsecret;
            var response = apiclient.getjson<accesstokenresponse>(url);
            return response;
        }

        /// <summary>
        /// 获取jsapiticket
        /// </summary>
        /// <param name="accesstoken"></param>
        /// <returns></returns>
        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<accessticketresponse>(url);

            return response?.ticket;
        }

        /// <summary>
        /// 获取签名
        /// </summary>
        /// <param name="jsapi_ticket"></param>
        /// <param name="noncestr">随机字符串(必须与wx.config中的noncestr相同)</param>
        /// <param name="timestamp">时间戳(必须与wx.config中的timestamp相同)</param>
        /// <param name="url">当前网页的url,不包含#及其后面部分(必须是调用js接口页面的完整url)</param>
        /// <returns></returns>
        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());
        }
       
        /// <summary>
        /// sha1加密签名
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        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;
        }

    }
  • 签名定义的model
public class accesstokenresponse: baseresponse
    {
        /// <summary>
        /// 返回access_token值,有效期7200秒
        /// </summary>
        public string access_token { get; set; }
        /// <summary>
        /// 过期时间,单位小时
        /// </summary>
        public datetime expire_out { get; set; }


    }

    public class accessticketresponse : baseresponse
    {
        /// <summary>
        /// 返回ticket票据,有效期7200秒
        /// </summary>
        public string ticket { get; set; }

    }
  public class baseresponse
    {
        /// <summary>
        /// 过期时间,单位秒
        /// </summary>
        public string expire_in { get; set; }
        /// <summary>
        /// 错误代码
        /// </summary>
        public int32 errcode { get; set; }
        /// <summary>
        /// 错误信息描述
        /// </summary>
        public string errmsg { get; set; }
    }
  • 创建生成签名的时间戳和随机串
 /// <summary>
        /// 获取微信js-jdk时间戳
        /// </summary>
        /// <returns></returns>
        public static string gettimestamp()
        {
            timespan ts = datetime.utcnow - new datetime(1970, 1, 1, 0, 0, 0);

            return convert.toint64(ts.totalseconds).tostring();
        }
     
        /// <summary>
        /// js-jdk 创建随机字符串
        /// </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();
        }
  • action中实际调用
        [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;
            }
        }    

  注意:

  1. 签名用的noncestr和timestamp必须与wx.config中的noncestr和timestamp相同。
  2. 移动端分享时,不能本地测试,需要发布到外网测试,否则报签名错误
    1. .netcore2.1  JS-SDK  从后台获取微信签名,实现自定义分享标题、描述、图片
  3. 生成的签名,可以实用校验工具校验是否正确。