微信js sdk invalid signature簽名錯(cuò)誤問題的解決方法分析
本文實(shí)例講述了微信js sdk invalid signature簽名錯(cuò)誤問題的解決方法。分享給大家供大家參考,具體如下:
/**最近在做微信js sdk 接口調(diào)用說明*/
***相信很多人都遇見像我這樣的問題,再加上自己只能算是半個(gè)程序員,所以苦苦摸索了好久終于搞懂了。
****下面就把自己所遇見的各種問題和大家分享一下,都是自己親手實(shí)驗(yàn)過的********/
一、問題說明
如果出現(xiàn) invalid signature,首先可以確定的是你的簽名算法有問題。
建議:首先查看微信官方網(wǎng)站給出的解決方案,鏈接為 http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
invalid signature簽名錯(cuò)誤。建議按如下順序檢查:
2. 確認(rèn)簽名算法正確,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 頁面工具進(jìn)行校驗(yàn)。也就是你自己后臺(tái)生成簽名要和微信校驗(yàn)算法生成的簽名一致才可以(可能大小寫不同)。
3. 注意:
簽名生成規(guī)則如下:
參與簽名的字段包括有效的 jsapi_ticket(獲取方式詳見微信 JSSDK 文檔), noncestr (隨機(jī)字符串,由開發(fā)者隨機(jī)生成),timestamp (由開發(fā)者生成的當(dāng)前時(shí)間戳), url(當(dāng)前網(wǎng)頁的URL,不包含#及其后面部分。注意:對(duì)于沒有只有域名沒有 path 的 URL ,瀏覽器會(huì)自動(dòng)加上 / 作為 path,如打開 http://qq.com 則獲取到的 URL 為 http://qq.com/)。
特別注意:你在利用參數(shù)生成簽名的時(shí)候,要對(duì)所有待簽名參數(shù)按照字段名的 ASCII 碼從小到大排序(字典序)后,使用 URL 鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串 string1。這里需要注意的是所有參數(shù)名均為小寫字符。
我的最開始的錯(cuò)誤就是沒有注意到生成簽名的那幾個(gè)參數(shù)要按照key=value的樣式連接成一個(gè)字符串,然后在sha1加密生成。
/****Java寫的參數(shù)拼接算法***/ String[] paramArr = new String[] { "jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonce, "url=" + jsurl }; Arrays.sort(paramArr); // 將排序后的結(jié)果拼接成一個(gè)字符串 String content = paramArr[0].concat("&"+paramArr[1]).concat("&"+paramArr[2]) .concat("&"+paramArr[3]); System.out.println("拼接之后的content為:"+content);
4. 確認(rèn)config中nonceStr(js中駝峰標(biāo)準(zhǔn)大寫S), timestamp與用以簽名中的對(duì)應(yīng)noncestr, timestamp一致。
5. 確認(rèn)url是頁面完整的url(請(qǐng)?jiān)诋?dāng)前頁面alert(location.href.split('#')[0])確認(rèn)),包括'http(s)://'部分,以及'?'后面的GET參數(shù)部分,但不包括'#'hash后面的部分。
6. 確認(rèn) config 中的 appid 與用來獲取 jsapi_ticket 的 appid 一致。
7. 確保一定緩存access_token和jsapi_ticket。
8. 確保你獲取用來簽名的url是動(dòng)態(tài)生成的,動(dòng)態(tài)頁面可參見實(shí)例代碼中php的實(shí)現(xiàn)方式。如果是html的靜態(tài)頁面在前端通過ajax將url傳到后臺(tái)簽名,前端需要用js獲取當(dāng)前頁面除去'#'hash部分的鏈接(可用location.href.split('#')[0]獲取),因?yàn)轫撁嬉坏┓窒?,微信客戶端?huì)在你的鏈接末尾加入其它參數(shù),如果不是動(dòng)態(tài)獲取當(dāng)前鏈接,將導(dǎo)致分享后的頁面簽名失敗。
錯(cuò)誤2、每次后臺(tái)網(wǎng)頁更新之后,微信訪問效果沒有出來。
問題:手機(jī)端,網(wǎng)頁緩沖導(dǎo)致。
解決方案:重啟手機(jī),再試一下。
錯(cuò)誤3、微信分享接口,可以在自己的網(wǎng)頁上面自定義一個(gè)按鈕,當(dāng)用戶點(diǎn)擊的時(shí)候完成分享。
問題:我最開始也是這樣想的,后來發(fā)現(xiàn),原來不是這樣的,只有當(dāng)你用微信客戶端打開,在最上面右邊的 “分享到朋友圈”按鈕按的時(shí)候效果才會(huì)出來。
錯(cuò)誤4、微信圖像接口 permission denied
首先查看微信給出的錯(cuò)誤說明:該公眾號(hào)沒有權(quán)限使用這個(gè)JSAPI(部分接口需要認(rèn)證之后才能使用)。
說明:只要通過了公眾號(hào)認(rèn)證,都不會(huì)有問題。
檢查對(duì)象:如果出現(xiàn)這個(gè)說明程序上基本上不會(huì)有問題 微信后臺(tái)已經(jīng)返回了數(shù)據(jù)。
第一、要檢查 你的config 文件中相應(yīng)的 jsapilist 是否包含了該接口喲。
/***用戶打開頁面的時(shí)候就加載**/ $(document).ready(function(){ initPage(); }); function initPage() { //alert(window.location.href);/***用于獲得當(dāng)前連接url用**/ /***用戶點(diǎn)擊分享到微信圈后加載接口接口*******/ $.post("http://******",{"url":window.location.href},function(data,status){ data=eval("("+data+")"); wx.config({ debug: false, appId: 'wxa7a1ad4cc5116437', timestamp:data.timestamp, nonceStr:data.noncestr, signature:data.signature, jsApiList: [ 'checkJsApi', 'onMenuShareTimeline', 'hideOptionMenu', ] }); wx.ready(function(){ wx.hideOptionMenu();/***隱藏分享菜單****/ }); }); };
說明:這一塊我是通過寫一個(gè)方法,然后用戶用AJax 的post 獲得這樣的請(qǐng)求,然后參數(shù)是URL。
二、實(shí)例說明
獲得jsticket
public static String getjsTicket(String accesstoken) { String appid = "XXXXXXX"; String appsecret = "XXXX"; String result = ""; String url = js_ticketurl.replace("ACCESS_TOKEN", accesstoken); System.out.println("查看js_url:" + url); // 調(diào)用接口返回json字符串 JSONObject jsonObject = httpRequest(url, "GET", ""); System.out.println("查看紅的js_ticket:" + jsonObject.toString()); if (null != jsonObject) { result = jsonObject.getString("ticket");// 獲得ticket System.out.println("ticket為:" + result); } return result; }
獲得signature
// 獲得js signature public static String getSignature(String jsapi_ticket, String timestamp, String nonce, String jsurl) throws IOException { /**** * 對(duì) jsapi_ticket、 timestamp 和 nonce 按字典排序 對(duì)所有待簽名參數(shù)按照字段名的 ASCII * 碼從小到大排序(字典序)后,使用 URL 鍵值對(duì)的格式(即key1=value1&key2=value2…)拼接成字符串 * string1。這里需要注意的是所有參數(shù)名均為小寫字符。 接下來對(duì) string1 作 sha1 加密,字段名和字段值都采用原始值,不進(jìn)行 * URL 轉(zhuǎn)義。即 signature=sha1(string1)。 * **如果沒有按照生成的key1=value&key2=value拼接的話會(huì)報(bào)錯(cuò) */ String[] paramArr = new String[] { "jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonce, "url=" + jsurl }; Arrays.sort(paramArr); // 將排序后的結(jié)果拼接成一個(gè)字符串 String content = paramArr[0].concat("&"+paramArr[1]).concat("&"+paramArr[2]) .concat("&"+paramArr[3]); System.out.println("拼接之后的content為:"+content); String gensignature = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); // 對(duì)拼接后的字符串進(jìn)行 sha1 加密 byte[] digest = md.digest(content.toString().getBytes()); gensignature = byteToStr(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } // 將 sha1 加密后的字符串與 signature 進(jìn)行對(duì)比 if (gensignature != null) { return gensignature;// 返回signature } else { return "false"; } // return (String) (ciphertext != null ? ciphertext: false); } /** * 將字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串 * * @param byteArray * @return */ private static String byteToStr(byte[] byteArray) { String strDigest = ""; for (int i = 0; i < byteArray.length; i++) { strDigest += byteToHexStr(byteArray[i]); } return strDigest; } /** * 將字節(jié)轉(zhuǎn)換為十六進(jìn)制字符串 * * @param mByte * @return */ private static String byteToHexStr(byte mByte) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] tempArr = new char[2]; tempArr[0] = Digit[(mByte >>> 4) & 0X0F]; tempArr[1] = Digit[mByte & 0X0F]; String s = new String(tempArr); return s; }
希望本文所述對(duì)大家微信程序設(shè)計(jì)有所幫助。
相關(guān)文章
有關(guān)IntelliJ IDEA中LeetCode插件配置問題
這篇文章主要介紹了關(guān)于IntelliJ IDEA中LeetCode插件配置問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08Java中BigDecimal類與int、Integer使用總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中BigDecimal類與int、Integer使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07關(guān)于Java項(xiàng)目讀取resources資源文件路徑的那點(diǎn)事
這篇文章主要介紹了關(guān)于Java項(xiàng)目讀取resources資源文件路徑的那點(diǎn)事,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Java使用JDBC實(shí)現(xiàn)Oracle用戶認(rèn)證的方法詳解
這篇文章主要介紹了Java使用JDBC實(shí)現(xiàn)Oracle用戶認(rèn)證的方法,結(jié)合實(shí)例形式分析了java使用jdbc實(shí)現(xiàn)數(shù)據(jù)庫連接、建表、添加用戶、用戶認(rèn)證等操作流程與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08詳解RabbitMQ延遲隊(duì)列的基本使用和優(yōu)化
這篇文章主要介紹了詳解RabbitMQ延遲隊(duì)列的基本使用和優(yōu)化,延遲隊(duì)列中的元素都是帶有時(shí)間屬性的。延遲隊(duì)列就是用來存放需要在指定時(shí)間被處理的元素的隊(duì)列,需要的朋友可以參考下2023-05-05詳解Spring Security中獲取當(dāng)前登錄用戶的詳細(xì)信息的幾種方法
本文主要介紹了詳解Spring Security中獲取當(dāng)前登錄用戶的詳細(xì)信息的幾種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05SpringBoot使用Feign進(jìn)行服務(wù)間通信的實(shí)現(xiàn)示例代碼
Feign是一個(gè)開源的Java HTTP客戶端,可以幫助我們?cè)赟pringBoot應(yīng)用中快速構(gòu)建和使用HTTP客戶端,方便實(shí)現(xiàn)服務(wù)間的通信,本文就來介紹一下SpringBoot使用Feign進(jìn)行服務(wù)間通信的實(shí)現(xiàn)示例代碼,感興趣的可以了解一下2024-01-01Java設(shè)計(jì)模式中的裝飾器模式簡(jiǎn)析
這篇文章主要介紹了Java設(shè)計(jì)模式中的裝飾器模式簡(jiǎn)析,裝飾模式能夠?qū)崿F(xiàn)動(dòng)態(tài)的為對(duì)象添加功能,是從一個(gè)對(duì)象外部來給對(duì)象添加功能,通常給對(duì)象添加功能,要么直接修改對(duì)象添加相應(yīng)的功能,要么派生對(duì)應(yīng)的子類來擴(kuò)展,抑或是使用對(duì)象組合的方式,需要的朋友可以參考下2023-12-12