The idea of separating the front and back ends of wechat third-party login

The front-end implementation

When the page is loaded, declare a variable state=’ timestamp + 6-bit random number ‘, and the front-end path generates a TWO-DIMENSIONAL code, in which there is a state parameter that we need to pass. If you pass this parameter, wechat will return something to you when it is called back. We use the state generated before. When the user clicks the button of wechat login, we connect with the back end through websocket with the state value as key, and the TWO-DIMENSIONAL code page pops up at the same time. State is like a token for the front end, telling the back end who is using wechat to log in. The purpose is that when the background receives the callback, it can accurately return the data to the user currently scanning the code. The background can get the code value and the state value during the wechat callback, and obtain the access_token and OpenID through the code, and request the latest information of the wechat user through these two values. The back end defines what the returned status value represents in one of two status codes: 1. Bound: Retrieves the user information and returns it to the front end via websocket, 2. Unbound: Returns the openID and avatar nickname of the wechat account. The front end receives the Websocket information sent by the back end and determines the wechat binding status. If the bound route is redirected to the login completion page; if not, it is redirected to the binding or registration page.

The first step

The front end is set to generate the path of two-dimensional code,

this.url =
      "https://open.weixin.qq.com/connect/qrconnect?appid=" +
      this.appid +
      "&redirect_uri=" +
      this.redirect_uri +
      "&response_type=code&scope=snsapi_login&state=" +
      this.state +
      "#wechat_redirect";

Copy the code

Parameter Description (The parameters to be modified are explained here)

Parameter names note
appid This is the appID of wechat login application
redirect_uri Wechat callback address, remember to url transcoding here
state This is wechat to our own parameters, no matter what you pass, will be returned to you in the callback back

The second step

The user clicks on the wechat login page and connects with the back end through websocket. The key of the connection is the state in the connection of the TWO-DIMENSIONAL code we produce

 let wsname = "ws://www.niezhiliang.com:8086/socketServer/" + this.state;
      this.ws = new WebSocket(wsname);
      // The connection was successfully triggered
      this.ws.onopen = function(evt) {};// This is a method to receive messages sent by the background
      this.ws.onmessage = function(evt) {
        var data = JSON.parse(evt.data);
        console.log(data)
       // Check whether the state given by the background is 1 or 2 and perform the corresponding operation
      })

Copy the code

Then the TWO-DIMENSIONAL code page pops up (shown in the center)

//this.url= we concatenated it when the page loaded
WxLogin() {
      this.itop = (window.screen.availHeight - 500) / 2;
      // Get the horizontal position of the window
      this.ileft = (window.screen.availWidth - 400) / 2;
      this.w = window.open(
        this.url,
        "newwindow"."height=500, width=400, top=" +
          this.itop +
          ", left = " +
          this.ileft +
          ", toolbar=no, menubar=no,scrollbars=no, resizable=no,location=no, status=no"
      );
    }
Copy the code

Back-end Java implementation (websocket will not explain, if you do not understand can see my other project)

Github.com/niezhiliang…

The first step

Here’s the code for webSocket

  • Configure the WebSocket connection service
@ServerEndpoint(value = "/socketServer/{userid}")
@Component
public class SocketServer {

	private Session session;
	private static Map<String,Session> sessionPool = new HashMap<String,Session>();
	private static Map<String,String> sessionIds = new HashMap<String,String>();

	/** * Triggered when the user connects@param session
	 * @param userid
	 */
	@OnOpen
	public void open(Session session,@PathParam(value="userid")String userid){
		this.session = session;
		sessionPool.put(userid, session);
		sessionIds.put(session.getId(), userid);
	}

	/** * Triggered when a message is received@param message
	 */
	@OnMessage
	public void onMessage(String message){
		System.out.println("Current sender sessionID is"+session.getId()+"Send content as"+message);
	}

	/** * Connection closure trigger */
	@OnClose
	public void onClose(a){
		sessionPool.remove(sessionIds.get(session.getId()));
		sessionIds.remove(session.getId());
	}

	/** * Triggered when an error occurs@param session
	 * @param error
	 */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

	/** * How to send messages *@param message
	 * @param userId
	 */
	public static void sendMessage(String message,String userId){
		Session s = sessionPool.get(userId);
		if(s! =null) {try {
				s.getBasicRemote().sendText(message);
			} catch(IOException e) { e.printStackTrace(); }}}}Copy the code
  • Provides an API for sending information to the front end
    @RequestMapping(value = "/sendpost")
    public String sendPost(@RequestBody Params params) {
        if (params.getJson() == null || params.getUserid() == null) {
            return "error";
        }
        logger.info(params.getJson()+"-- -- -- -- -- -- -- -- -- -- -"+params.getUserid());
        SocketServer.sendMessage(params.getJson(),params.getUserid());
        return "success";
    }
Copy the code

The second step

Here is the wechat callback code

 /** * wechat scan callback *@return* /
    @RequestMapping(value = "/callback")
    public void callBack(Device device) {
        String code = request.getParameter("code");
        String state = request.getParameter("state");
        RespInfo respInfo = new RespInfo();
        respInfo.setStatus(InfoCode.ERROR);
        if(code ! =null) {
            StringBuffer url = new StringBuffer();
            / * * * * * * * * * access token * * * * * * * * * * * * /
            url.append(request_url)
                    .append("appid=")
                    .append(appid)
                    .append("&secret=")
                    .append(secret)
                    .append("&code=")
                    .append(code)
                    .append("&grant_type=")
                    .append(grant_type);
            logger.info(url.toString());
			 // Call wechat API method to query user basic information
            JSONObject jsonObject =
                    JSON.parseObject(HttpUtil.getResult(url.toString()));
            // Get openID and request wechat API use token
            String openid =jsonObject.get("openid").toString();
            String token = jsonObject.get("access_token").toString();

            / * * * * * * * * * get the userinfo * * * * * * * * * * * * /
            url = new StringBuffer();
            url.append(userinfo_url)
                    .append("access_token=")
                    .append(token)
                    .append("&openid=")
                    .append(openid);
            logger.info(url.toString());
            // Use the token and openID above to obtain the basic information of the user
            String result = HttpUtil.getResult(url.toString());
            WeixinInfo weixinInfo = JSON.parseObject(result,WeixinInfo.class);
            if(weixinInfo ! =null) {
               // This method is to remove the special symbols of wechat nicknames. In order to avoid saving database operation exceptions, I replaced all nickname emoticons with *
                weixinInfo.setNickname(filterEmoji(weixinInfo.getNickname()));
                // Insert database operation
                weiXinService.insertOrUpdateSelective(weixinInfo);
            }
            // Use openID to find out if the user is bound
            User user = userService.getByOpenId(openid);
            if (user == null) {// The wechat account is not bound to any account
                respInfo.setStatus(InfoCode.INVALID_TOKEN);
                respInfo.setMessage("Please register before logging in to wechat");
                Map<String,Object> map = new HashMap<String,Object>();
                map.put("openid",openid);
                map.put("headimgurl",weixinInfo.getHeadimgurl());
                map.put("nickname",weixinInfo.getNickname());
                respInfo.setContent(map);
            } else {// This means that the wechat has been bound to the user account, directly return the user login information
                respInfo.setStatus(InfoCode.SUCCESS);
                respInfo.setContent(user);
            }
        }
        String json = JSON.toJSONString(respInfo);
        /************websocket responds to the data to the front-end **************/
        Map map = new HashMap();
        map.put("userid",state);
        map.put("json",json);
        String params = JSON.toJSONString(map);
        try {
            // The result is returned to the front end via websocketSystem. Out.println (HttpUtil doPost (" HTTP:/ / www.niezhiliang.com:8086/websocket/sendpost "params));
        } catch(Exception e) { e.printStackTrace(); }}Copy the code