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