Logic and implementation of WeChat web page login

Keywords: Javascript SDK github Webpack

Website development now can not bypass Wechat login (after all, Wechat has become a national tool).Although the documentation is detailed, it is easy for inexperienced developers to tread on holes.

Therefore, it is convenient to record the interactive logic of WeChat Web page authentication and review it later:

  1. Load the WeChat web page sdk
  2. Draw landing codes: new tab page drawing / iframe drawing of this page
  3. User Scavenger Logon, Front End Jump Callback URL
  4. Callback web addresses are further logically processed, and if in-page iframe draws a QR code, the top page needs to be notified

(vii) Read more series of articles / Read the original text

WeChat Web SDK Loading

In multi-person team collaboration, code that loads resources requires extra care.This can cause duplicate loading of resources because multiple developers may call it under the same business logic.

There are two ways to handle this. The first is to expose redundant interfaces externally, specifically to check whether duplicate loading occurs.However, considering that the caller needs to explicitly call the check() method to check each time before loading, there will inevitably be omissions.

So take the second approach, the cache mode in design mode, with the following code:

// Memo mode: prevent duplicate loading
export const loadWeChatJs = (() => {
  let exists = false; // Docking
  const src = '//Res.wx.qq.com/connect/zh_CN/htmleedit/js/wxLogin.js'; //WeChat sdk web address

  return () => new Promise((resolve, reject) => {
    // Prevent duplicate loading
    if(exists) return resolve(window.WxLogin);
    
    let script = document.createElement('script');
    script.src = src;
    script.type = 'text/javascript';
    script.onerror = reject; // TODO: Remove script tags when failing
    script.onload = () => {
      exists = true;
      resolve(window.WxLogin);
    };
    document.body.appendChild(script);
  });
})();

Draw landing codes

according to WeChat Landing Development Guide , pass the parameter to window.WxLogin().

// WeChat Default Configuration
const baseOption = {
  self_redirect: true, // true: in-page iframe jump; false: new tab open 
  id: 'wechat-container', 
  appid: 'wechat-appid',
  scope: 'snsapi_login',
  redirect_uri: encodeURIComponent('//1.1.1.1/'),
  state: '',
};

export const loadQRCode = (option, intl = false, width, height) => {
  const _option = {...baseOption, ...option};

  return new Promise((resolve, reject) => {
    try {
      window.WxLogin(_option);
      const ele = document.getElementById(_option['id']);
      const iframe = ele.querySelector('iframe');
      iframe.width = width? width : '300';
      iframe.height = height? height : '420'; 
      // Handle internationalization
      intl && (iframe.src = iframe.src + '&lang=en');
      resolve(true);
    } catch(error) {
      reject(error);
    }
  });
};

Among the business components you need to use, you can call them in the periodic function componentDidMount, with demo code below:

componentDidMount() {
    const wxOption = {
        // ...
    };
    loadWeChatJs()
        .then(WxLogin => loadQRCode(wxOption))
        .catch(error => console.log(`Error: ${error.message}`));   
}

Callback web address communicates with iframe

This piece of logic I think is the most complex and difficult to understand in WeChat's landing interaction.As mentioned at the beginning, there are two ways to render WeChat QR codes, one is to open a new tab, the other is to insert iframe into a container with a specified id.

Undoubtedly, the second way of interacting is more user-friendly, because code processing is more challenging when it comes to page communication at different levels.

For illustration purposes, first look at the simulated data configuration:

// The redirect address is taken by the back end, the back end is redirected to this address, and the front end visits this page
// Parameters in the redirect address are reserved for use by front-end personnel; the back-end adds more fields to meet business needs and returns to the front-end together
const querystr = '?' + stringify({
  redirect: encodeURIComponent(`${window.location.origin}/account/redirect?` + stringify({
    to: encodeURIComponent(window.location.origin),
    origin: encodeURIComponent(window.location.origin),
    state: 'login'
  })),
  type: 'login'
});

const wxOption = {
  id: 'wechat-container',
  self_redirect: true,
  redirect_uri: encodeURIComponent(`//1.1.1/api/socials/weixin/authorizations${querystr}`//WeChat callback request address
};

Front and Back End, WeChat Server, Client Interaction Logic

Following the configuration above, I describe the logic of front-end, client, WeChat server and back-end interaction:

  1. The front-end loads a two-dimensional code based on wxOption, and all information is placed in the two-dimensional code.Also listens for messages from the WeChat server.
  2. User mobile scanner informs Wechat server to confirm landing.
  3. The WeChat server receives the user's scanner request and forwards it to the front end.
  4. The front end receives a message from the WeChat server and jumps to this url address based on the redirect_uri parameter of wxOption.Be careful:

    • This interface address is backend and requested by GET
    • Front end carries parameters by splicing params
    • The address is spliced into a temporary token from the WeChat server, which is given to the back end in exchange for the user's public key
  5. The backend receives a request from/api/socials/weixin/authorizations${querystr} to decode the information in the querystr.Then request the user's public key from the WeChat service.Root out the front-end conventions (the redirect field is used in demo), redirect to the redirect field specified in the front-end, and stitch together more information such as user public keys.
  6. Front End knows redirection and jumps to the redirected route (account/redirect is used in demo)
  7. After the corresponding routing process, data such as user keys from the end-end can be processed.
  8. At this point, the four-end interactive logic of WeChat authentication is completed

Cross Iframe Communication

The previous process is complete, and now the two-dimensional code area of the iframe on the page has been replaced with the contents of / account/redirect?...

In order to communicate, you need to listen for the message event during the cycle of the page and uninstall it when the component is uninstalled:

componentDidMount() {
  // ... ...
  
  window.addEventListener('message', this.msgReceive, false);
}

componentWillUnmount() {
  window.removeEventListener('message', this.msgReceive);
}

msgReceive(event) {
  // Is monitoring a secure iframe?
  if(!event.isTrusted) {
    return;
  }
  console.log(event.data); // Get data from iframe for further logical processing
}

In the component corresponding to the route, /account/redirect?..., we need to parse the params parameter in the route and pass the result to the previous page after checking according to business logic:

componentDidMount() {
    // step1: Get the params parameter in the url
    const querys = getQueryVariable(this.props.location.search);
    // step2: Check that the data in queries meets the requirements... 
    // step3: Deliver messages to top-level pages
    return window.parent && window.parent.postMessage('data', '*');
}

At this point, the process of WeChat web page authentication is completed.

More: For more details on iframe communication, check the MDN documentation

More Series Articles

Collection/Subscription on GitHub

Front End Knowledge System

Design Mode Manual

Webpack4 Progressive Tutorial

Collection/Subscription on GitHub

Posted by darkjedig on Tue, 14 May 2019 13:48:29 -0700