小程序登錄態維持

這幾天一直在搞小程序,對於其登錄態的維持和後臺運行機制一直有些困惑。

花了很多時間完成了,這裏可以給新手指條路,也給自己做個筆記。

分爲下面幾個方面來講

  • 常規Web項目登錄態維持
  • 小程序的特殊點
  • 如何在小程序中實現登錄態的維持


一、常規Web項目登錄態維持

這裏就文字簡述一下,關於Web項目登錄態維持網上資料實在是很多,不累贅了。

1.用戶打開頁面——服務端接受請求,給予頁面,並給其創建一個會話(通過sessionID來標誌這個客戶端,sessionID保存在服務端)。

     F12就可以看到,你在同一個網站登錄後,所有請求的Cookie值都不會變。

2.在後臺我們開發的時候,在登錄時會在session中保存當前用戶的姓名,用戶ID等,在程序開時可以直接從session中取得使用;爲什麼能從session取得當前用戶的ID,而不會和其他用戶混淆呢?

//可以看到session從request中取得,然而request中就包含了請求的所有信息,包括sessionID來認識你的當前會話
//只要你的sessionID與服務器中緩存的sessionID相同,服務端就認識你,你就能取得那一塊的session緩存數據。
//這樣就維持了針對客戶端的會話概念。
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session=request.getSession();//獲取session
session.setAttribute(arg0, arg1);//往session裏保存鍵值對
session.getAttribute(name);//根據key取得value

String sessionID=session.getId();//從客戶端取得sessionID,sessionID在客戶端保存名爲JSESSIONID,一般web項目,一次會話的sessionID不變,而小程序每次請求都會變。。。。所以小程序並沒有會話的概念
二、小程序的特殊點


新手需要先去看看小程序的簡易教程,然後下個開發者工具,看一下默認的項目結構。

1.小程序前臺與後臺開發分離,但是不存在跨域問題,因爲一次請求的順序是這樣的:小程序 —>微信服務端 —>第三方服務端(也就是你的後臺)—>微信服務端—>小程序。

2.如上也就意味着小程序中不存在會話的概念,無法在session中保存用戶ID等信息,只能通過自己的手段解決。同時,小程序與微信服務端也會維持登錄態。

3.那麼暴露的後臺如何保證登錄與後續身份驗證的安全性呢?登錄:使用code請求openid驗證用戶身份;後續身份驗證:登錄後將你自己的sessionID用自己的邏輯實現,維持小程序與第三方服務端的登錄態,而sessionID保存在小程序中。

4.我們來看看,其他開發小程序的同志的困難吧,同時也佐證上幾條。

(官方邏輯圖)


(官方論壇提問)

(官方回答)



所以,其實官方論壇裏的邏輯圖是不對的,無法保存在session中,有人也許會說保存在ServletContext,可是這不常規,影響性能,且無法定時清除。

下面是一些帖子,還有很多其他看過的帖子,一個意思,我沒保存就不貼了。

其他用戶帖子

微信官方論壇帖子

三、小程序如何維護登錄態

這裏是我綜合大部分邏輯和觀點的登錄態維護代碼,已經實現,從頭開始一步一步把代碼貼出來。

     1.之前說過,小程序是與微信後臺服務對接的,他們之間也有登錄態,如下wx.login()就是小程序與微信後臺登錄,從login中能獲取code,發到第三方後臺,獲取你自己的登錄態。

//用戶登錄公共方法
  userLogin:function(){
    var me=this;
    // 登錄
    wx.login({
      success: res => {
        // 發送 res.code 到後臺換取 openId, sessionKey, unionId
        var errMsg = res.errMsg;
        if (errMsg != "login:ok") {
          me.showHint("錯誤提示","出錯了,請稍後再試試...")
        } else {
          var code = res.code; //(獲取code代碼)
          wx.request({
            url: 'http://localhost:8080/wxCode/sys_login', //僅爲示例,並非真實的接口地址
            data: {
              code: code
            },
            header: {
              'content-type': 'application/json' // 默認值
            },
            success: function (res) {//code去後臺換取openid,且將uuid(sessionID保存到前臺),最好保存在localstrage,但是官方獲取localstrage方法有時候會出錯,就保存到app全局變量中了。
              var data = JSON.parse(res.data);
               me.globalData.name = data.name;
               me.globalData.Cookie = data.uuid;
               me.globalData.openid = data.openID;
              if (data.hint == "NOUser") {
              } else {
               
                wx.redirectTo({
                  url: '../sysPage/choseFunc',
                })
                me.showHint("登錄提示", data.successMark > 0 ? "登錄成功!" : "登錄失敗!請重新登錄!");
              }
            }
          })
        }

      }
    })
  },

2.後臺獲取openid,這裏就是請求地址,獲取openid,因爲code唯一,一次性,只要能從code獲取openid就能保證是從小程序登錄的正確用戶(請求用https,官方已經申明不支持http請求了)
//發送推送請求
		public static JSONObject sendGet(String URLParam) {
			
			  JSONObject backJSON=null;
			 try {
				 final String ADD_URL = URLParam;
		            //創建連接
		            URL url = new URL(ADD_URL);//創建java url對象
		            HttpsURLConnection connection = (HttpsURLConnection) url
		            		.openConnection();//創建該對象的https請求
		            connection.setDoOutput(true);//設置請求允許向對方服務器傳輸
		            connection.setDoInput(true);//設置請求允許己方接收傳輸
		            connection.setRequestMethod("POST");//設置傳輸方式POST
		            connection.setUseCaches(false);//POST請求不允許設置緩存
		            connection.setInstanceFollowRedirects(true);
		            connection.setRequestProperty("Content-Type",
		                    "application/x-www-form-urlencoded");
		            connection.connect();//建立鏈接

		            //POST請求
		            DataOutputStream out = new DataOutputStream(
		                    connection.getOutputStream());

		           // out.write(obj.toString().getBytes("UTF-8"));//傳輸中文需要標明轉碼格式
		            out.flush();
		            out.close();

		            //讀取響應
		            BufferedReader reader = new BufferedReader(new InputStreamReader(
		                    connection.getInputStream()));//接收流
		            String lines;
		            StringBuffer sb = new StringBuffer("");
		            while ((lines = reader.readLine()) != null) {
		                lines = new String(lines.getBytes(), "ASCII");
		                sb.append(lines);
		            }//讀取返回的數據
		            reader.close();
		            // 斷開連接
		            connection.disconnect();
		            System.out.print(sb);
		            backJSON=JSONObject.parseObject(sb.toString());
//		            String back=sb.toString();
//		            int x=back.indexOf(":");
//		            int y=back.indexOf(",");
//		            errcode=back.substring(x+1,y);
		        } catch (MalformedURLException e) {
		            // TODO Auto-generated catch block
		            e.printStackTrace();
		        } catch (UnsupportedEncodingException e) {
		            // TODO Auto-generated catch block
		            e.printStackTrace();
		        } catch (IOException e) {
		            // TODO Auto-generated catch block
		            e.printStackTrace();
		        }
			return backJSON;
		}
	    
	//獲取微信用戶信息
	public static JSONObject getWXUserInfo(String code)  {		
		//ruanxing小程序
		String appid = "AAAAAAAAAAAAAAAAAAAA";
		String secret = "BBBBBBBBBBBBBBBBBBBBBBBBBBBB";
		String URLParam = "https://api.weixin.qq.com/sns/jscode2session?appid="+appid+""
				+ "&secret="+secret+"&js_code="+code;
		

		//發送 GET 請求
     //System.out.println(authURL);
     JSONObject backJSON = wxFunc.sendGet(URLParam);

		return backJSON;
	}

3.後臺我就不貼了,你們可以根據自己的業務邏輯識別openid,且將uuid(sessionID)保存在服務器中,無論你是啥形式都可以,我是保存在數據庫中的,因爲沒法用session啊啊啊啊,媽的智障騰訊。(這裏還有一點,如果是要實現自己的業務邏輯,就需要一個openid綁定業務賬號的過程,這個自己解決吧)

4.封裝wx.request(),並將uuid帶入header頭部信息;

//封裝小程序ajax請求。
  /**
   * header自動cookie
   * 自動判斷是否登錄超時,退出登錄邏輯
   * 自動轉化data爲JSON對象
   * **/
  sendRequest:function(json){
    var me=this;
    wx.request({
      url: json.url,
      data: json.data,
      method: 'GET',
      header: {
        'content-type': 'application/json', // 默認值,
        'Cookie': "uuid=" + me.globalData.Cookie //這個方法放在app.js中,作爲全局方法,且自動將Cookie帶入。
      },
      success: function (res) {//封裝登錄超時或錯誤自動退出邏輯
        var data=JSON.parse(res.data);
        if (data.ifSuccess =="NeedLogin"){
          wx.redirectTo({
            url: '../index/index',
          })
          me.showHint("登錄提示", "登錄超時,請關閉小程序重新登錄!");
        }else{
          json.success(data);
        }
      },
      fail: function (res) {
        var data = JSON.parse(res.data);
        json.fail(data);
        //console.log(".....fail.....");
      }
    })
  },

//使用方法
app.sendRequest({
url:"http://localhost:8080/wxCode/business_getDataOfSKD",
data:{
},
success:function(data){
console.log(data);
}
});

5.後臺獲取wx.request中的hearder的cookie信息。

HttpServletRequest request = ServletActionContext.getRequest(); 
		Cookie[] cookies = request.getCookies();//這樣便可以獲取一個cookie數組
	 	for(Cookie cookie : cookies){
	 		if(cookie.getName().equals("uuid")){
	 			uuid=cookie.getValue();
	 		}
	 	}
//實現自己的業務邏輯............
四、總結

1.小程序是前後臺分離,微信服務器訪問第三方服務器。

2.每個技術BAT企業都會犯錯,官方文檔概念模糊,錯亂,再所難免。

3.多看API多看論壇,多理思路,但API不可全信,還是網友思路靠譜。


如有錯誤和不對的地方,麻煩指正哦


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章