微信第三方登入前後端分離實現思路
阿新 • • 發佈:2019-12-31
微信第三方登入前後端分離實現思路
前端實現
這裡說一下前後端的思路,頁面載入時宣告一個變數
state
='時間戳+6位隨機數',前端路徑生成二維碼, 其中有個state
引數需要我們傳遞,這個引數你傳什麼,微信回撥的時候就會給你返回什麼。 我們用之前生成那個state,當使用者點選微信登入的按鈕,我們就通過以state值為key和後端進行websocket連線,同時彈出二維碼頁面。 state對前端來說就相當於一個令牌,告訴後端是誰在使用微信登入。目的在於,當後臺收到回撥的時候,能準確的把資料返回當前掃碼的使用者, 後臺在微信回撥的時候能拿到code
的值和state
的值,通過code
去拿access_token
和openid
, 通過這兩個值去請求微信使用者最新資訊, 後端定義好返回的狀態值代表啥,無非兩種狀態碼:1.已經繫結:取出user
資訊, 通過websocket返回給前端,2.沒繫結:返回微信賬戶的openid和頭像暱稱。 前端收到後端傳送的websocket資訊,判斷微信繫結狀態,如果繫結路由跳轉到登入完成頁面,如果未繫結,跳轉到繫結或註冊頁面。
第一步
前端先設定好生成二維碼的路徑,
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";
複製程式碼
引數解釋(這裡直解釋需要修改的引數)
引數名 | 備註 |
---|---|
appid | 這個就是申請微信登入應用的appid |
redirect_uri | 微信的回撥地址,記得這裡要url轉碼 |
state | 這個是微信給我們自己傳遞的引數,不管你傳的是啥,都會在回撥中給你返回回來 |
第二步
使用者點選微信登入頁面,和後端進行websocket連線,連線的key就是我們生產二維碼連線中的state
let wsname = "ws://www.niezhiliang.com:8086/socketServer/" + this.state;
this.ws = new WebSocket(wsname);
//連線成功觸發
this.ws.onopen = function(evt) {
};
//這個是接收後臺傳送資訊的方法
this.ws.onmessage = function(evt) {
var data = JSON.parse(evt.data);
console.log(data)
//在這裡判斷後臺給的狀態是1還是2 並進行相應的操作
})
複製程式碼
然後再彈出二維碼頁面(居中顯示)
//this.url=我們在頁面載入的時候拼接好的
WxLogin() {
this.itop = (window.screen.availHeight - 500) / 2;
//獲得視窗的水平位置
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"
);
}
複製程式碼
後端Java實現(websocket就不解釋啦,如果不懂可以去看我的另一個專案)
第一步
這邊是websocket的程式碼
- 配置websocket連線服務
@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>();
/**
* 使用者連線時觸發
* @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);
}
/**
* 收到資訊時觸發
* @param message
*/
@OnMessage
public void onMessage(String message){
System.out.println("當前傳送人sessionid為"+session.getId()+"傳送內容為"+message);
}
/**
* 連線關閉觸發
*/
@OnClose
public void onClose(){
sessionPool.remove(sessionIds.get(session.getId()));
sessionIds.remove(session.getId());
}
/**
* 發生錯誤時觸發
* @param session
* @param error
*/
@OnError
public void onError(Session session,Throwable error) {
error.printStackTrace();
}
/**
*資訊傳送的方法
* @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();
}
}
}
}
複製程式碼
- 提供給前端傳送資訊的api
@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";
}
複製程式碼
第二步
這邊是微信回撥程式碼
/**
* 微信掃碼回撥
* @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();
/*********獲取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());
//呼叫微信查詢使用者基本資訊的api方法
JSONObject jsonObject =
JSON.parseObject(HttpUtil.getResult(url.toString()));
//拿到openid和請求微信api使用的token
String openid =jsonObject.get("openid").toString();
String token = jsonObject.get("access_token").toString();
/*********獲取userinfo************/
url = new StringBuffer();
url.append(userinfo_url)
.append("access_token=")
.append(token)
.append("&openid=")
.append(openid);
logger.info(url.toString());
//通過上面拿到的token和openid獲取使用者的基本資訊
String result = HttpUtil.getResult(url.toString());
WeixinInfo weixinInfo = JSON.parseObject(result,WeixinInfo.class);
if (weixinInfo != null) {
//這個方法是為了去除微信暱稱的特殊符號,為了避免儲存資料庫操作報異常我把所有的暱稱表情都替換成了*
weixinInfo.setNickname(filterEmoji(weixinInfo.getNickname()));
//插入資料庫操作
weiXinService.insertOrUpdateSelective(weixinInfo);
}
//通過openid去找使用者是否繫結
User user = userService.getByOpenId(openid);
if (user == null) {//說明該微信未繫結任何賬號
respInfo.setStatus(InfoCode.INVALID_TOKEN);
respInfo.setMessage("請先註冊再進行微信綁登入操作");
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 {//這裡是表示該微信已經綁定了使用者賬號,直接返回使用者登入資訊就好
respInfo.setStatus(InfoCode.SUCCESS);
respInfo.setContent(user);
}
}
String json = JSON.toJSONString(respInfo);
/************websocket將資料響應給前端**************/
Map map = new HashMap();
map.put("userid",state);
map.put("json",json);
String params = JSON.toJSONString(map);
try {
//這裡是將結果通過websocket返回給前端
System.out.println(HttpUtil.
doPost(“http://www.niezhiliang.com:8086/websocket/sendpost”,params));
} catch (Exception e) {
e.printStackTrace();
}
}
複製程式碼