微信公衆號接入(參考微信開放文檔記筆記)

接入概述

接入微信公衆平臺開發,開發者需要按照如下步驟完成:

1、填寫服務器配置

2、驗證服務器地址的有效性

3、依據接口文檔實現業務邏輯

下面詳細介紹這3個步驟。

第一步:填寫服務器配置

登錄微信公衆平臺官網後,在公衆平臺官網的開發-基本設置頁面,勾選協議成爲開發者,點擊“修改配置”按鈕,填寫服務器地址(URL)、Token和EncodingAESKey,其中URL是開發者用來接收微信消息和事件的接口URL。Token可由開發者可以任意填寫,用作生成簽名(該Token會和接口URL中包含的Token進行比對,從而驗證安全性)。EncodingAESKey由開發者手動填寫或隨機生成,將用作消息體加解密密鑰。

同時,開發者可選擇消息加解密方式:明文模式、兼容模式和安全模式。模式的選擇與服務器配置在提交後都會立即生效,請開發者謹慎填寫及選擇。加解密方式的默認狀態爲明文模式,選擇兼容模式和安全模式需要提前配置好相關加解密代碼,詳情請參考消息體簽名及加解密部分的文檔 。

第二步:驗證消息的確來自微信服務器

開發者提交信息後,微信服務器將發送GET請求到填寫的服務器地址URL上,GET請求攜帶參數如下表所示:

參數 描述
signature 微信加密簽名,signature結合了開發者填寫的token參數和請求中的timestamp參數、nonce參數。
timestamp 時間戳
nonce 隨機數
echostr 隨機字符串

開發者通過檢驗signature對請求進行校驗(下面有校驗方式)。若確認此次GET請求來自微信服務器,請原樣返回echostr參數內容,則接入生效,成爲開發者成功,否則接入失敗。加密/校驗流程如下:

1)將token、timestamp、nonce三個參數進行字典序排序 2)將三個參數字符串拼接成一個字符串進行sha1加密 3)開發者獲得加密後的字符串可與signature對比,標識該請求來源於微信

這是一個servlet文件,用來處理微信發過來的認證請求;

package myservlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class MyServlet
 */
public class MyServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public MyServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter pw = response.getWriter();
        String signature =  request.getParameter("signature");
        String timestamp = request.getParameter("timestamp");
        String nonce = request.getParameter("nonce");
        String echostr = request.getParameter("echostr");
        boolean isSuccess = CheckUtil.check(signature, timestamp, nonce);
        if(isSuccess) {
            pw.print(echostr);
            pw.write("接入成功!");
        }
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}

驗證方法

public class CheckUtil {

    public static final String token  ="##";

    public static boolean check(String signature,String timestamp,String nonce ) {
        String arrs[] = {token,timestamp,nonce};
        Arrays.sort(arrs);//字典排序
        //拼接字符串
        StringBuffer sb = new  StringBuffer();
        for(String str :arrs) {
            sb.append(str);
        }
        String signaturesha1 = Sha1Util.encode(sb.toString());
        return  signaturesha1.equals(signature);
    }

}

sha1加密

package myservlet;

import java.security.MessageDigest;

public final class Sha1Util {

    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
            'e', 'f' };

    /**
     * 
        * @Title: getFormattedText
        * @Description: TODO(這裏用一句話描述這個方法的作用)
        * @param @param bytes
        * @param @return    參數
        * @return String    返回類型
        * @throws
     */
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        // 把密文轉換成十六進制的字符串形式
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }

    /**
     * 
        * @Title: encode
        * @Description: TODO(這裏用一句話描述這個方法的作用)
        * @param @param str
        * @param @return    參數
        * @return String    返回類型
        * @throws
     */
    public static String encode(String str) {
        if (str == null) {
            return null;
        }
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
            messageDigest.update(str.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <servlet>
    <!--servlet名稱,可以自定義-->
    <servlet-name>MyServlet</servlet-name>
    <!-- servlet類名: 包名+簡單類名-->
    <servlet-class>myservlet.MyServlet</servlet-class>
  </servlet>

  <servlet-mapping>
    <!--servlet名稱,應與上面的名稱保持一致,因爲是通過下面的servlet訪問名稱來定位到上面的servlet名稱,再通過上面的名稱定位到servlet類的位置-->
    <servlet-name>MyServlet</servlet-name>
    <!-- servlet的訪問名稱: /名稱 -->
    <url-pattern>/helloMyServlet.do</url-pattern>
  </servlet-mapping>
</web-app>

原理

  • 將token,timestamp,nonce進行字典排序,拼接成一個字符串。
  • 將字符串進行sha1加密。
  • 將加密後的字符創和signature比較。true則提交成功,請原樣返回echostr參數內容;false則爲失敗。

獲取Access token

access_token是公衆號的全局唯一接口調用憑據,公衆號調用各接口時都需使用access_token。開發者需要進行妥善保存。access_token的存儲至少要保留512個字符空間。access_token的有效期目前爲2個小時,需定時刷新,重複獲取將導致上次獲取的access_token失效。

公衆平臺的API調用所需的access_token的使用及生成方式說明:

1、建議公衆號開發者使用中控服務器統一獲取和刷新access_token,其他業務邏輯服務器所使用的access_token均來自於該中控服務器,不應該各自去刷新,否則容易造成衝突,導致access_token覆蓋而影響業務;

2、目前access_token的有效期通過返回的expire_in來傳達,目前是7200秒之內的值。中控服務器需要根據這個有效時間提前去刷新新access_token。在刷新過程中,中控服務器可對外繼續輸出的老access_token,此時公衆平臺後臺會保證在5分鐘內,新老access_token都可用,這保證了第三方業務的平滑過渡;

3、access_token的有效時間可能會在未來有調整,所以中控服務器不僅需要內部定時主動刷新,還需要提供被動刷新access_token的接口,這樣便於業務服務器在API調用獲知access_token已超時的情況下,可以觸發access_token的刷新流程。

4、對於可能存在風險的調用,在開發者進行獲取 access_token調用時進入風險調用確認流程,需要用戶管理員確認後纔可以成功獲取。具體流程爲:

開發者通過某IP發起調用->平臺返回錯誤碼[89503]並同時下發模板消息給公衆號管理員->公衆號管理員確認該IP可以調用->開發者使用該IP再次發起調用->調用成功。

如公衆號管理員第一次拒絕該IP調用,用戶在1個小時內將無法使用該IP再次發起調用,如公衆號管理員多次拒絕該IP調用,該IP將可能長期無法發起調用。平臺建議開發者在發起調用前主動與管理員溝通確認調用需求,或請求管理員開啓IP白名單功能並將該IP加入IP白名單列表。

公衆號和小程序均可以使用AppID和AppSecret調用本接口來獲取access_token。AppID和AppSecret可在“微信公衆平臺-開發-基本配置”頁中獲得(需要已經成爲開發者,且帳號沒有異常狀態)。**調用接口時,請登錄“微信公衆平臺-開發-基本配置”提前將服務器IP地址添加到IP白名單中,點擊查看設置方法,否則將無法調用成功。**小程序無需配置IP白名單。

接口調用請求說明

https請求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

參數說明

參數 是否必須 說明
grant_type 獲取access_token填寫client_credential
appid 第三方用戶唯一憑證
secret 第三方用戶唯一憑證密鑰,即appsecret

返回說明

正常情況下,微信會返回下述JSON數據包給公衆號:

{"access_token":"ACCESS_TOKEN","expires_in":7200}

參數說明

參數 說明
access_token 獲取到的憑證
expires_in 憑證有效時間,單位:秒

錯誤時微信會返回錯誤碼等信息,JSON數據包示例如下(該示例爲AppID無效錯誤):

{"errcode":40013,"errmsg":"invalid appid"}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章