1. 程式人生 > >用ssm進行微信開發,實現微信登入驗證功能

用ssm進行微信開發,實現微信登入驗證功能

1.微信測試號後臺配置

注意,這個配置要成功,否則是會顯示配置失敗的。後臺怎麼寫,看下面

2.後臺程式碼

2.1驗證token的程式碼

控制器裡:

@RequestMapping(value = "/wxcheck")
public void check(Model model, HttpServletRequest request, HttpServletResponse response)throws IOException {
    boolean isGet = request.getMethod().toLowerCase().equals("get");
    PrintWriter print;
    if(isGet){
        // 微信加密簽名
        String signature = request.getParameter("signature");
        // 時間戳
        String timestamp = request.getParameter("timestamp");
        // 隨機數
        String nonce = request.getParameter("nonce");
        // 隨機字串
        String echostr = request.getParameter("echostr");
        // 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
        if (signature != null && WechatUtil.checkSignature(signature, timestamp, nonce)) {
            try {
                print = response.getWriter();
                print.write(echostr);
                print.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

WechatUtil這個工具類:

public class WechatUtil {
    /**
     * 與介面配置資訊中的Token要一致
     */
    private static String token = "20180806";

    /**
     * 驗證簽名
     *
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static boolean checkSignature(String signature, String timestamp, String nonce) {
        String[] arr = new String[] { token, timestamp, nonce };
        // 將token、timestamp、nonce三個引數進行字典序排序
        // Arrays.sort(arr);
        sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // 將三個引數字串拼接成一個字串進行sha1加密
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        content = null;
        // 將sha1加密後的字串可與signature對比,標識該請求來源於微信
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }

    /**
     * 將位元組陣列轉換為十六進位制字串
     *
     * @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;
    }

    /**
     * 將位元組轉換為十六進位制字串
     *
     * @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;
    }
    public static void sort(String a[]) {
        for (int i = 0; i < a.length - 1; i++) {
            for (int j = i + 1; j < a.length; j++) {
                if (a[j].compareTo(a[i]) < 0) {
                    String temp = a[i];
                    a[i] = a[j];
                    a[j] = temp;
                }
            }
        }
    }
}

這麼一來,微信通過token驗證我們的伺服器就能通過了。

2.獲取微信授權資訊

首先按鈕的格式:這個是比較麻煩的地方,格式必須一模一樣

{

    "button": [

        {



            "type": "click",

            "name": "暢迪用法",

            "key": "1"



        },

        {

            "name": "常見問題",

            "sub_button": [

                {

                    "type": "view",

                    "name": "關於過敏性疾病",

                    "url": "http://www.wolwobiotech.com/web2016/1.html"

                },

                {

                    "type": "view",

                    "name": "關於脫敏治療",

                    "url": "http://www.wolwobiotech.com/web2016/2.html"

                },

                {

                    "type": "view",

                    "name": "暢迪相關常見問題",

                    "url":  "http://www.wolwobiotech.com/web2016/4.html"

                }

            ]

        },

        {

            "name":"個人中心",

            "sub_button":[

                {

                    "type": "view",

                    "name": "測試",

                      "url" : "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxXXXXX95&redirect_uri=http%3A%2F%2FXXXXXXXXXXcom%2Flxxxxxxe%2Fauth&response_type=code&scope=snsapi_base&state=123#wechat_redirect"

                },

                {

                    "type": "click",

                    "name": "我要提問",

                    "key" : "103"

                }

            ]

        }

    ]

}

我使用的是基本方法不獲取userinfor,是默認同意授權的,控制器裡的寫法

 @RequestMapping(value = "/auth")
    public void wxAuth(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");

        // 使用者同意授權後,能獲取到code
        String code = request.getParameter("code");
        String state = request.getParameter("state");
        String url= "";

        // 使用者同意授權
        if (!"authdeny".equals(code)) {
            // 獲取網頁授權access_token
            WeixinOauth2Token weixinOauth2Token = WechatUtil.getOauth2AccessToken("id", "密碼", code);
            // 網頁授權介面訪問憑證
            String accessToken = weixinOauth2Token.getAccessToken();
            // 使用者標識
            String openId = weixinOauth2Token.getOpenId();
            String ip = IpUtil.getIpAddr(request);
            WxOpenid wxOpenid = new WxOpenid();
            wxOpenid.setIp(ip);
            wxOpenid.setCreatTime(new Date());
            wxOpenid.setOpenid(openId);
            int i = wxOpenidService.insertSelective(wxOpenid);
            System.out.println(">>>>>>>>>>>>>>>>>>>>"+ip);
//            // 獲取使用者資訊
//            SNSUserInfo snsUserInfo = AdvancedUtil.getSNSUserInfo(accessToken, openId);

            // 設定要傳遞的引數
//            request.setAttribute("snsUserInfo", snsUserInfo);
//            request.setAttribute("state", state);

        }
        url = "http://xxx/xxx/";
        // 跳轉到langya前臺
        response.sendRedirect(url);

    }

用到的工具類:

 /**
     * 獲取網頁授權憑證
     *
     * @param appId 公眾賬號的唯一標識
     * @param appSecret 公眾賬號的金鑰
     * @param code
     * @return WeixinAouth2Token
     */
    public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
        WeixinOauth2Token wat = new WeixinOauth2Token();
        // 拼接請求地址
        String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        requestUrl = requestUrl.replace("APPID", appId);
        requestUrl = requestUrl.replace("SECRET", appSecret);
        requestUrl = requestUrl.replace("CODE", code);
        // 獲取網頁授權憑證
        JSONObject jsonObject = HttpCommonUtil.httpsRequest(requestUrl, "GET", null);
        if (null != jsonObject) {
            try {
                wat.setAccessToken(jsonObject.getString("access_token"));
                wat.setExpiresIn(jsonObject.getInteger("expires_in"));
                wat.setRefreshToken(jsonObject.getString("refresh_token"));
                wat.setOpenId(jsonObject.getString("openid"));
                wat.setScope(jsonObject.getString("scope"));
            } catch (Exception e) {
//                wat = null;
//                int errorCode = jsonObject.getInteger("errcode");
//                String errorMsg = jsonObject.getString("errmsg");
//                log.error("獲取網頁授權憑證失敗 errcode:{} errmsg:{}", errorCode, errorMsg);
            }
        }
        return wat;
    }

還有一個網頁授權資訊的實體類:

/**
 * 類名: WeixinOauth2Token </br>
 * 描述:  網頁授權資訊  </br>
 * 開發人員: fr</br>
 * 釋出版本:V1.0  </br>
 */
public class WeixinOauth2Token {
    // 網頁授權介面呼叫憑證
    private String accessToken;
    // 憑證有效時長
    private int expiresIn;
    // 用於重新整理憑證
    private String refreshToken;
    // 使用者標識
    private String openId;
    // 使用者授權作用域
    private String scope;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public int getExpiresIn() {
        return expiresIn;
    }

    public void setExpiresIn(int expiresIn) {
        this.expiresIn = expiresIn;
    }

    public String getRefreshToken() {
        return refreshToken;
    }

    public void setRefreshToken(String refreshToken) {
        this.refreshToken = refreshToken;
    }

    public String getOpenId() {
        return openId;
    }

    public void setOpenId(String openId) {
        this.openId = openId;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

還有一個傳送http請求的工具類

package com.wolwo.base.util;


import com.alibaba.fastjson.JSONObject;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import java.security.SecureRandom;
import javax.net.ssl.*;

public class HttpCommonUtil {

    /**
     * 傳送https請求
     *
     * @param requestUrl 請求地址
     * @param requestMethod 請求方式(GET、POST)
     * @param outputStr 提交的資料
     * @return JSONObject(通過JSONObject.get(key)的方式獲取json物件的屬性值)
     */
    public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
        JSONObject jsonObject = null;
        try {
            // 建立SSLContext物件,並使用我們指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new SecureRandom());
            // 從上述SSLContext物件中得到SSLSocketFactory物件
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
            conn.setSSLSocketFactory(ssf);

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 設定請求方式(GET/POST)
            conn.setRequestMethod(requestMethod);

            // 當outputStr不為null時向輸出流寫資料
            if (null != outputStr) {
                OutputStream outputStream = conn.getOutputStream();
                // 注意編碼格式
                outputStream.write(outputStr.getBytes("UTF-8"));
                outputStream.close();
            }

            // 從輸入流讀取返回內容
            InputStream inputStream = conn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str = null;
            StringBuffer buffer = new StringBuffer();
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }

            // 釋放資源
            bufferedReader.close();
            inputStreamReader.close();
            inputStream.close();
            inputStream = null;
            conn.disconnect();
            jsonObject  = JSONObject.parseObject(buffer.toString());
        } catch (ConnectException ce) {
//            log.error("連線超時:{}", ce);
        } catch (Exception e) {
//            log.error("https請求異常:{}", e);
        }
        return jsonObject;
    }
}
package com.wolwo.base.util;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;

/**
 * 類名: MyX509TrustManager </br>
 * 描述:信任管理器 </br>
 * 開發人員: fr</br>
 * 釋出版本:V1.0  </br>
 */
public class MyX509TrustManager implements X509TrustManager {

    // 檢查客戶端證書
    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    // 檢查伺服器端證書
    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
    }

    // 返回受信任的X509證書陣列
    public X509Certificate[] getAcceptedIssuers() {
        return null;
    }
}

這麼一來就行了