刘耀文

刘耀文

java开发者
github

微信公眾號登錄網站

需求:微信公眾號登錄網站,獲取用戶信息

前提條件#

  1. 微信公眾號已經認證
  2. 擁有伺服器,可以接收微信伺服器的回調

步驟#

1、獲取微信公眾號的 appid 和 appsecret#

2、接入伺服器,接收微信伺服器的回調,需要有域名,可以使用內網穿透工具,例如 cpolar#

首先需要準備好圖中的資源#

image

說明:

  • URL 表示微信驗證服務端是否存在,需要按照要求進行配置,例如我這裡的地址是

    https://13a34511.r1.cpolar.top/api/user/wxcheck
    

    所以必須在自己的服務上準備好響應的接口

    //外層還有/user
    @GetMapping("wxcheck")
    public String  wxCheck(@RequestParam("signature") String signature,
                                        @RequestParam("timestamp") String timestamp,
                                        @RequestParam("nonce") String nonce,
                                        @RequestParam("echostr") String echostr) {
        if (userService.wxCheck(signature, timestamp, nonce, wxOpenConfig.getToken())) {
            return echostr;
        } else {
            return "error";
        }
    }
    

    需要按照微信的要求返回數據,要求如下:

    1)將 token、timestamp、nonce 三個參數進行字典序排序

    2)將三個參數字符串拼接成一個字符串進行 sha1 加密

    3)開發者獲得加密後的字符串可與 signature 對比,標識該請求來源於微信

        @Override
        public Boolean wxCheck(String signature, String timestamp, String nonce, String token) {
            // 微信公眾號接入校驗
            // 將token、timestamp、nonce三個參數進行字典序排序
            String[] arr = new String[]{token, timestamp, nonce};
            Arrays.sort(arr);
            // 將三個參數字符串拼接成一個字符串進行sha1加密
            StringBuilder content = new StringBuilder();
            for (String s : arr) {
                content.append(s);
            }
            String tmpStr = MYDigestUtils.sha1DigestAsHex(content.toString());
    
            log.info("微信公眾號接入校驗,signature = {}, tmpStr = {}", signature, tmpStr);
            return signature.equals(tmpStr);
        }
    

    接著提交上面的表單後會提示驗證通過

3、接下來就是獲取 access_token 了#

Mermaid Loading...
  • 需要根據要求返回訪問微信資源的 token,訪問微信中的資源必須要這個 token,例如後續的二維碼
@Override
public String getAccessToken() {
    // 獲取access_token
    String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
                               wxOpenConfig.getAppId(), wxOpenConfig.getAppSecret());
    // 發送請求
    String result = restTemplate.getForObject(url, String.class);
    log.info("獲取access_token,result = {}", result);
    return result;
}

4、生成帶 Ticket 二維碼#

    @Override
    public String getQRCode(String accessToken) {
        // 獲取二維碼
        String url = String.format("https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=%s", accessToken);
        // 5分鐘過期
        String body = WXUtils.getQRCodeBody("300", "QR_STR_SCENE");
        String result = restTemplate.postForObject(url, body, String.class);
        log.info("獲取二維碼,result = {}", result);
        return result;
    }

5、將二維碼的 ticket 返回給前端,前端請求到二維碼圖片展示給用戶#

6、用戶掃碼後會將響應的事件推送給上面的 URL, 只是將 GET 請求轉換為 POST 請求,格式為:#

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[FromUser]]></FromUserName>
  <CreateTime>123456789</CreateTime>
  <MsgType><![CDATA[event]]></MsgType>
  <Event><![CDATA[subscribe]]></Event>
  <EventKey><![CDATA[qrscene_123123]]></EventKey>
  <Ticket><![CDATA[TICKET]]></Ticket>
</xml>

當然有很多事件類型,我們可以定義策略模式分別處理

@Slf4j
public class DispatchEventHandle {

    private final Map<String, EventHandle> eventHandleMap = new HashMap<>();

    {
        eventHandleMap.put("subscribe", new SubscribeEventHandle());
        eventHandleMap.put("SCAN", new ScanEventHandle());
    }

    public  void dispatch(JSONObject jsonObject) {
        String eventType = jsonObject.getJSONObject("xml").getStr(WxEventHandleConstants.EVENT_TYPE_KEY);
        log.info("事件類型:{}", eventType);
        EventHandle eventHandle = eventHandleMap.get(eventType);
        if (eventHandle == null) {
            log.error("未找到對應的事件處理器");
            return;
        }
        eventHandle.handle(jsonObject);

    }
}

接收請求的接口定義為

    @PostMapping("wxcheck")
    public String  event(@RequestBody String xml) {
        String msgType = WXUtils.getMsgType(xml);
        if ("event".equals(msgType)) {
            DispatchEventHandle dispatchEventHandle = new DispatchEventHandle();
            dispatchEventHandle.dispatch(JSONUtil.xmlToJson(xml));
        }
        return xml;
    }

7、前端在展示二維碼後記得要輪詢伺服器,看是否已經掃描,後端可以在處理完成後將 ticket 作為 key,JWT 作為值快取,前端請求查詢到後順利登錄;#

此文由 Mix Space 同步更新至 xLog 原始鏈接為 https://me.liuyaowen.club/posts/default/1

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。