1. 程式人生 > 程式設計 >微信第三方登入前後端分離實現思路

微信第三方登入前後端分離實現思路

微信第三方登入前後端分離實現思路

前端實現

這裡說一下前後端的思路,頁面載入時宣告一個變數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就不解釋啦,如果不懂可以去看我的另一個專案)

github.com/niezhiliang…

第一步

這邊是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();
        }
    }
複製程式碼