深入理解Session與Cookie

此文知識來自于:《深入分析Java_Web技術(shù)》第十章
現(xiàn)代session與cookie的應(yīng)用


本章概要:
當我們的一個應(yīng)用系統(tǒng)有幾百臺服務(wù)器時项郊,如何解決Session在多臺服務(wù)器之間共享的問題枯途?它們還有一些安全問題,如Cookie被盜、Cookie偽造等問題應(yīng)如何避免仅乓?Session與Cookie的作用都是為了保持訪問用戶與后端服務(wù)器的交互狀態(tài)收毫。例如,使用Cookie來傳遞信息時风纠,隨著Cookie個數(shù)的增多和訪問量的增加,它占用的網(wǎng)絡(luò)帶寬也很大牢贸,試想假如Cookie占用200個字節(jié)竹观,如果一天的PV有幾億,那么它要占用多少帶寬潜索?所以有大訪問量時希望用Session臭增,但是Session的致命弱點是不容易在多臺服務(wù)器之間共享,這也限制了Session的使用竹习。

1. 理解Cookie

Cookie的作用通俗地說就是當一個用戶通過HTTP訪問一個服務(wù)器時誊抛,這個服務(wù)器會將一些Key/Value鍵值對返回給客戶端瀏覽器,并給這些數(shù)據(jù)加上一些限制條件整陌,在條件符合時這個用戶下次訪問這個服務(wù)器時拗窃,數(shù)據(jù)又被完整地帶回給服務(wù)器。

當初W3C設(shè)計Cookie時實際考慮的是為了記錄用戶在一段時間內(nèi)訪問Web應(yīng)用的行為路徑泌辫。由于HTTP是一種無狀態(tài)協(xié)議随夸,當用戶的一次訪問請求結(jié)束后,后端服務(wù)器就無法知道下一次來訪問的還是不是上次訪問的用戶震放。例如宾毒,在一個很短的時間內(nèi),如果與用戶相關(guān)的數(shù)據(jù)被頻繁訪問殿遂,可以針對這個數(shù)據(jù)做緩存伍俘,這樣可以大大提高數(shù)據(jù)的訪問性能邪锌。Cookie的作用正是如此,由于是同一個客戶端發(fā)出的請求癌瘾,每次發(fā)出的請求都會帶有第一次訪問時觅丰,服務(wù)端設(shè)置的信息,這樣服務(wù)端就可以根據(jù)Cookie值來劃分訪問的用戶了妨退。

1.1 Cookie屬性項

當前Cookie有兩個版本:Version0和Version1妇萄,它們有兩種設(shè)置響應(yīng)頭的標識,分別是“Set-Cookie”和“Set-Cookie2”咬荷。它們屬性項有些不同冠句。

Version0屬性項:

屬性項 屬性項介紹
NAME=VALUE 設(shè)置要保存的Key/Value,注意這里的NAME不能和其它屬性項的名字一樣
Expires 過期時間
Domain 生成該Cookie的域名
Path 該Cookie是在當前哪個路徑下生成的
Secure 如果設(shè)置了這個屬性幸乒,那么只會在SSH連接時才會回傳該Cookie
Expires 過期時間

在Java Web的Servlet規(guī)范并不支持Set-Cookie2響應(yīng)頭懦底,在實際應(yīng)用中Set-Cookie2的一些屬性項卻可以設(shè)置在Set-Cookie中。博主在查看Cookie源碼罕扎,發(fā)現(xiàn)是支持的:


另外也可以從源碼可以得知聚唐,一般所說的Cookie鍵值對,都是值NAME和VALUE屬性腔召,其實Cookie還有其他的屬性杆查,通過Get/Set方法進行獲取和設(shè)置。
另外下面是博主在使用Chrome瀏覽器查看的Cookie:

1.2 Cookie如何工作

當我們用如下方式創(chuàng)建Cookie時:

String getCookie(Cookie[] cookies, String key) {
    if (cookies != null) {
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(key)) {
                return cookie.getValue();
            }
        }
    }
    return null;
}

@Override
public void doGet(HttpServletRequest req, HttpServletResponse res) {
    Cookie[] cookies = req.getCookies();
    String userName = getCookie(cookies, "userName");
    String userAge = getCookie(cookies, "userAge");
    if (userName == null) {
        res.addCookie(new Cookie("userName", "liwenguang"));
    }
    if (userAge == null) {
        res.addCookie(new Cookie("userAge", "22"));
    }
    res.getHeaders("Set-Cookie");
}

以下幾點需要注意:

  • 所創(chuàng)建Cookie的NAME不能和Set-Cookie或者Set-Cookie2的屬性項值一樣臀蛛。
  • 所創(chuàng)建Cookie的NAME和VALUE的值不能設(shè)置成非ASCII字符亲桦,如果要使用中文,可以通過URLEncoder將其編碼浊仆。
  • 當NAME和VALUE的值出現(xiàn)一些TOKEN字符(如“\”客峭、“,”等)時抡柿,構(gòu)建返回頭會將該Cookie的Version自動設(shè)置為1舔琅。
  • 當在該Cookie的屬性項中出現(xiàn)Version為1的屬性項時,構(gòu)建HTTP響應(yīng)頭同樣會將Version設(shè)置為1沙绝。

1.3 使用Cookie的限制

任何語言對Cookie的操作,其實都是讓瀏覽器對Cookie的操作鼠锈,Cookie的瀏覽器的特性闪檬,而瀏覽器對Cookie有數(shù)量限制(50個/每個域名),總大小限制(4096购笆,Chrome沒有這個限制)粗悯。

2 理解Session

前面已經(jīng)介紹了Cookie可以讓服務(wù)端程序跟蹤每個客戶端的訪問,但是每次客戶端的訪問都必須傳回這些Cookie同欠,如果Cookie很多样傍,則無形地增加了客戶端
與服務(wù)端的數(shù)據(jù)傳輸量横缔,而Session的出現(xiàn)正是為了解決這個問題。

同一個客戶端每次和服務(wù)端交互時衫哥,不需要每次都傳回所有的Cookie值茎刚,而是只要傳回一個ID,這個ID是客戶端第一次訪問服務(wù)端時生成的撤逢,而且每個客戶端是唯一的膛锭。
這樣每個客戶端就有了一個唯一的ID,客戶端只要傳回這個ID就行了蚊荣,這個ID通常是NAME為JSESIONID的一個Cookie初狰。

2.1 Session與Cookie

下面詳解講一下Session是如何基于Cookie來工作的。實際上有以下三種方式可以讓Session正常工作互例。

  • 基于URL Path Parameter奢入,默認支持。
  • 基于Cookie媳叨,如果沒有修改Context容器的Cookies標識腥光,則默認也是支持的。
  • 基于SSL肩杈,默認不支持柴我,只有connector.getAttribute("SSLEnabled")為TRUE時才支持。

在第一種情況扩然,當瀏覽器不支持Cookie功能時艘儒,瀏覽器會將用戶的SessionCookieName重寫到用戶請求的URL參數(shù)中,傳遞格式如/path/Servlet;name=value;name2=value2?Name3=value3夫偶,其中“Servlet界睁;”后面的K-V就是要傳遞的Path Parameters,服務(wù)器會從這個Path Parameters中拿到用戶配置的SessionCookieName兵拢。關(guān)于這個SessionCookieName翻斟,如果在web.xml中配置session-config配置項,其cookie-config下的name屬性就是這個SessionCookieName的值说铃。如果沒有配置sessio-config配置項访惜,默認的SessionCookieName就是大家熟悉的“JSESSIONID”。需要說明的一點是腻扇,與Session關(guān)聯(lián)的Cookie與其他Cookie沒有什么不同债热。接著Request根據(jù)這個SessionCookieName到Parameters中拿到Session ID并設(shè)置到request.setRequestedSessionId中。

請注意幼苛,如果客戶端也支持Cookie窒篱,則Tomcat仍然會解析Cookie中的Session ID,并會覆蓋URL中的Session ID。

如果是第三種情況墙杯,則會根據(jù)javax.servlet.request.ssl_session屬性值設(shè)置Session ID配并。

2.2 Session如何工作

有了Session ID,服務(wù)端就可以創(chuàng)建HttpSession對象了高镐,第一次觸發(fā)通過request.getSession()方法溉旋。如果當前的Session ID還沒有對應(yīng)的HttpSession對象,那么就創(chuàng)建一個新的避消,并將這個對象加到org.apache.catalina.Manager的session容器中保存低滩。Manager類將管理所有Session生命周期,Session過期將被回收岩喷,服務(wù)器關(guān)閉恕沫,Sessoin將被序列化到磁盤等。只要這個HttpSession對象存在纱意,用戶就可以根據(jù)Session ID來獲取這個對象婶溯,也就做到了對狀態(tài)的保持。


從Request中獲取的Session對象保存在org.apache.catalina.Manager類中偷霉,它的實現(xiàn)類是org.apache.catalina.session.StandardManager迄委,通過requestedSessionId從StandardManager的Sessions集合取出對應(yīng)的StandardSession對象。由于一個requestedSessionId對應(yīng)一個訪問的客戶端类少,所以一個客戶端也就對應(yīng)了一個StandardSession對象叙身,這個對象正是保存我們創(chuàng)建的Session值的。下面我們看一下StandardManager這個類是如何管理StandardSession的生命周期的硫狞。

StandardManager類負責Servlet容器中所有的StandardSession對象的生命周期管理信轿。當Servlet容器重啟或關(guān)閉時,StandardManager負責持久化沒有過期的StandardSession對象残吩,它會將所有的StandardSession對象持久化到一個以“SESSIONS财忽。ser”為文件名的文件中。到Servlet容器重啟時泣侮,也就是StandardManager初始化時即彪,它會重新讀取這個文件,解析出所有Session對象活尊,重新保存在StandardManager的sessions集合中隶校。

當Servlet容器關(guān)閉時StandardManager類會調(diào)用unload方法將session集合中的StandardSession對象寫到“SESSIONS.ser”文件中,然后在啟動時再重新恢復蛹锰,注意要持久化保存Servlet容器中的Session對象深胳,必須調(diào)用Servlet容器的stop的start命令,而不能直接結(jié)束(kill)Servlet容器的進程宁仔。
因為直接結(jié)束進程稠屠,Servlet容器沒有機會調(diào)用unload方法來持久化這些Session對象峦睡。

另外翎苫,在StandardManager的sessions集合中的StandardSession對象并不是永遠保存的权埠,否則Servlet容器的內(nèi)存將容易被消耗盡澳腹,所以必須給每個Session對象定義一個有效時間踩晶,超過這個時間則Session對象將被清除。在Tomcat中這個有效時間是60s(maxInactiveInterval屬性通知)政模,超過60s該Session將會過期呐粘。檢查每個Session是否失效是Tomcat的一個后臺線程中完成的满俗。

除了后臺進程檢查Session是否失效外,當調(diào)用request.getSession()時也會檢查該Session是否過期作岖。值得注意的是唆垃,request.getSession()方法調(diào)用的StandardSession永遠都會存在,即使與這個客戶端關(guān)聯(lián)的Session對象已經(jīng)過期痘儡。如果過期辕万,則又會重新創(chuàng)建一個全新的StandardSession對象,但是以前設(shè)置的Session值將會丟失沉删。如果你取到了Session對象渐尿,但是通過session.getAttribute取不到前面設(shè)置的Session值,請不要奇怪矾瑰,因為很可能已經(jīng)失效了砖茸,請檢查以下<Manager pathname="" maxInactiveInterval="60" />中maxInactiveInterval配置項的值,如果不想讓Session過期則可以設(shè)置為-1殴穴。但是你要仔細評估一下凉夯,網(wǎng)站的訪問量和設(shè)置的Session的大小,防止將你的Servlet容器內(nèi)存撐爆推正。如果不想自動創(chuàng)建Session對象恍涂,也可以通過request.getSession(bolean create)方法來判斷與該客戶端關(guān)聯(lián)的Session對象是否存在。

3 Cookie安全問題

Cookie通過把所有要保存的數(shù)據(jù)通過HTTP的頭部從客戶端傳遞到服務(wù)端植榕,又從服務(wù)端傳回到客戶端再沧,所有的數(shù)據(jù)都存儲在客戶端的瀏覽器里,所以這些Cookie數(shù)據(jù)可以被訪問到尊残,通過瀏覽器插件可以對Cookie進行修改等炒瘸。

相對而言Session的安全性要高很多,因為Session是將數(shù)據(jù)保存在服務(wù)端寝衫,只是通過Cookie傳遞一個SessionID而已顷扩,所以Session更適合存儲用戶隱私和重要的數(shù)據(jù)。

4 分布式Session框架

4.1 Cookie存在哪些問題

  • 客戶端Cookie存儲限制
  • Cookie管理的混亂慰毅,每個應(yīng)用系統(tǒng)都自己管理每個應(yīng)用使用的Cookie會導致混亂隘截,由于通常應(yīng)用系統(tǒng)都在同一個域名下,Cookie又有上面一條提到的限制,所以統(tǒng)一管理很容易出現(xiàn)Cookie超出限制的情況婶芭。
  • 不安全东臀,雖然通過設(shè)置HttpOnly屬性防止一些私密Cookie被客戶端訪問,但是仍然不能保證Cookie無法被篡改犀农。為了保證Cookie的私密性通常會對Cookie進行加密惰赋,但是維護這個加密Key也是一件麻煩的事情,無法保證定期更新加密Key也是會帶來安全性問題的一個重要因素呵哨。

4.2 Cookie+Session可以解決哪些問題

下面是分布式Session框架可以解決的問題:

  • Session配置的統(tǒng)一管理赁濒。
  • Cookie使用的監(jiān)控和統(tǒng)一規(guī)范管理。
  • Session存儲的多元化孟害。
  • Session配置的動態(tài)修改拒炎。
  • Session加密key的定期修改。
  • 充分的容災(zāi)機制挨务,保持框架的使用穩(wěn)定性枝冀。
  • Session各種存儲的監(jiān)控和報警支持。
  • Session框架的可擴展性耘子,兼容更多的Session機制如wapSession果漾。
  • 跨域名Session與Cookie如何共享的問題。現(xiàn)在同一個網(wǎng)站可能存在多個域名谷誓,如何將Session和Cookie在不同的域名之間共享是一個具有挑戰(zhàn)性的問題绒障。

4.3 總體實現(xiàn)思路

為了達成上面所說的幾個目標,我們需要一個服務(wù)訂閱服務(wù)器捍歪,在應(yīng)用啟動時可以從這個訂閱服務(wù)器訂閱這個應(yīng)用需要的可寫Session項和可寫Cookie項户辱,這些配置的Session和Cookie可以限制這個應(yīng)用能夠使用哪些Session和Cookie,甚至可以通知Session和Cookie可讀或可寫糙臼。這樣可以精確地控制哪些應(yīng)用可以操作哪些Session和Cookie庐镐,可以有效控制Session的安全性和Cookie的數(shù)量。


如Session的配置項可以為如下形式:

<sessions>
    <session>
        <key>sessionID</key>
        <cookiekey>sessionID</cookiekey>
        <lifeCycle>9000</lifeCycle>
        <base64>true</base64>
    </session>
    .......
</sessions>

Cookie的配置可以為如下形式:

<cookies>
    <cookie>
        <key>cookie</key>    
        <lifeCycle>10000</lifeCycle>
        <type>1</type>
        <path>/wp</path>
        <domain>liwenguang.website</domain>
        <decrypt>false</decrypt>
        <httpOnly>false</httpOnly>
    </cookie>
    ......
</cookies>

統(tǒng)一通過訂閱服務(wù)器推送配置可以有效地幾種管理資源变逃,所以可以省去每個應(yīng)用都來配置Cookie必逆,簡化Cookie的管理。如果應(yīng)用要使用一個新增的Cookie揽乱,則可以通過一個統(tǒng)一的平臺來申請名眉,申請通過才將這個配置項增加到訂閱服務(wù)器。如果是一個所有應(yīng)用都要使用的全局Cookie凰棉,那么只需要將這個Cookie通過訂閱服務(wù)器統(tǒng)一推送過去就行了损拢,省去了要在每個應(yīng)用中手動增加Cookie的配置。

關(guān)于這個訂閱服務(wù)器現(xiàn)在有很多開源的配置服務(wù)器撒犀,如ZooKeeper集群管理服務(wù)器福压,可以統(tǒng)一管理所有服務(wù)器的配置文件掏秩。

由于應(yīng)用是一個集群,所以不可能將創(chuàng)建的Session都保存在每臺應(yīng)用服務(wù)器的內(nèi)存中荆姆,因為如果每臺服務(wù)器有幾十萬的訪問用戶哗讥,那么服務(wù)器的內(nèi)存可能不夠用,即使內(nèi)存夠用胞枕,這些Session也無法同步到這個應(yīng)用的所有服務(wù)器中。所以要共享這些Session必須將它們存儲在一個分布式緩存中魏宽,可以隨時寫入和讀取腐泻,而且性能要很好才能滿足要求。當前能滿足這個要求的系統(tǒng)有很多队询,如MemCache或者淘寶的開源分布式緩存系統(tǒng)Tair都是很好的選擇派桩。

解決了配置和存儲問題,下面看一下如何存取Session和Cookie蚌斩。

既然是一個分布式Session的處理框架铆惑,必然會重新實現(xiàn)HttpSession的操作接口,使得應(yīng)用操作Session的對象都是我們實現(xiàn)的InnerHttpSession對象送膳,這個操作必須在進入應(yīng)用之前完成员魏,所以可以配置一個filter攔截用戶的請求。

先看一下如何封裝HttpSession對象和攔截請求叠聋,如下時序圖:


我們可以在應(yīng)用的web.xml中配置一個SessionFilter撕阎,用于在請求到達MVC框架之前封裝HttpServletRequest和HttpServletResponse對象,并創(chuàng)建我們自己的InnerHttpSession對象碌补,把它設(shè)置到request和response對象中虏束。這樣應(yīng)用系統(tǒng)通過request.getHttpSession()返回的就是我們創(chuàng)建的InnerHttpSession對象了,我們可以攔截response的addCookies設(shè)置的Cookie厦章。

在時序圖中镇匀,應(yīng)用創(chuàng)建的所有Session對象都會保存在InnerHttpSession對象中,當用戶的這次訪問請求完成時袜啃,Session框架將會把這個InnerHttpSession的所有內(nèi)容再更新到分布式緩存中汗侵,以便于這個用戶通過其它服務(wù)器再次訪問這個應(yīng)用系統(tǒng)。另外群发,為了保證一些應(yīng)用對Session穩(wěn)定性的特殊要求晃择,可以將一些非常關(guān)鍵的Session再存儲到Cookie中,如當分布式緩存存在問題時也物,可以將部分Session存儲到Cookie中宫屠,這樣即使分布式緩存出現(xiàn)問題也不會影響關(guān)鍵業(yè)務(wù)的正常運行。

4.4 增加Session跨域?qū)崿F(xiàn)

還有一個非常重要的問題就是如何處理跨域名來共享Cookie的問題滑蚯。我們知道Cookie是有域名限制的浪蹂,也就是在一個域名下的Cookie不能被另一個域名訪問抵栈,所以如果在一個域名下已經(jīng)登錄成功,如何訪問到另外一個域名的應(yīng)用且保證登錄狀態(tài)仍然有效坤次,對這個問題大型網(wǎng)站應(yīng)該經(jīng)常會遇到古劲。如何解決這個問題呢?
下面介紹一種處理方式缰猴,流程圖如下:


訪問域名A時服務(wù)器A獲得了session产艾,用戶訪問域名B時,如果發(fā)現(xiàn)服務(wù)器B沒有session滑绒,則302重定向跳轉(zhuǎn)到中轉(zhuǎn)服務(wù)器C(C你可以理解成專門取Session的域)闷堡,服務(wù)器C獲得了session后,則再進行302重定向到A服務(wù)器疑故,寫入session杠览,從而完成了session跨域。(如今纵势,大部分都是實現(xiàn)的單點登錄SSO踱阿,來解決子系統(tǒng)間的跨域問題,讓子系統(tǒng)共享頂級域名的Session钦铁、Cookie等)软舌。

5 Cookie壓縮

Cookie在HTTP的頭部,所以通常的gzip和deflate針對HTTP Body的壓縮不能壓縮Cookie牛曹,如果Cookie的量非常大葫隙,則可以考慮將Cookie也做壓縮,壓縮方式是將Cookie的多個k/v對看成普通的文本躏仇,做文本壓縮恋脚。壓縮算法同樣可以使用gzip和deflate算法,但是需要注意的一點是焰手,根據(jù)Cookie的規(guī)范糟描,在Cookie中不能包含控制字符,僅能包含ASCII碼為34~126的可見字符书妻。所以要將壓縮后的結(jié)果再進行轉(zhuǎn)碼船响,可以進行Base32或者Base64編碼。

// 使用DeflaterOutputStream壓縮后再用BASE64編碼
Cookie c = getCookieObject("");
HttpServletResponse res = getResponse();
ByteArrayOutputStream bos  = new ByteArrayOutputStream();
DeflaterOutputStream dos = new DeflaterOutputStream(bos);
try {
    dos.write(c.getValue().getBytes());
    dos.close();
    System.out.println("before compress length:" + c.getValue().length());
    String compress = new sun.misc.BASE64Encoder().encode(bos.toByteArray());
    res.addCookie(new Cookie("compress", compress));
    System.out.println("after compress length:" + compress.getBytes().length);
} catch (IOException e) {
    e.printStackTrace();
}
// 使用BASE64解碼后再用InflaterInputStream解壓
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
    byte[] compress = new sun.misc.BASE64Decoder().decodeBuffer(new String(c.getValue().getBytes()));
    ByteArrayInputStream bis = new ByteArrayInputStream(compress);
    InflaterInputStream inflater = new InflaterInputStream(bis);
    byte[] b = new byte[1024];
    int count;
    while ((count = inflater.read(b)) >= 0) {
        out.write(b, 0, count);
    }
    inflater.close();
    System.out.println(out.toByteArray());
} catch (IOException e) {
    e.printStackTrace();
}

6 表單重復提交問題

要防止表單重復提交躲履,就要標識用戶的每一次訪問請求见间,使得每一次訪問對服務(wù)端來說都是唯一確定的。為了標識用戶的每次訪問請求工猜,可以在用戶請求一個表單域時增加一個隱藏表單項米诉,這個表單項每次都是唯一的token,如:


當用戶第一次請求表單頁面時生成唯一的token篷帅,并存儲到用戶Session中史侣,當用戶第二次請求表單頁面時再生成唯一的token拴泌,覆蓋Session,這樣就能保證每次都只能通過請求表單頁面來提交表單惊橱。

7 多終端Session統(tǒng)一

當前大部分網(wǎng)站都有了無線端蚪腐,對無線端的Cookie如何處理也是很多程序員必須考慮的問題。
在無線端發(fā)展初期税朴,后端的服務(wù)系統(tǒng)未必和PC的服務(wù)系統(tǒng)是統(tǒng)一的回季,這樣就涉及在一端調(diào)用多個系統(tǒng)時如何做到服務(wù)端Session共享的問題了。有兩個明顯的例子:
一個是在無線端可能會通過手機訪問無線服務(wù)端系統(tǒng)正林,如果它們兩個的登錄系統(tǒng)沒有統(tǒng)一的話泡一,將會非常麻煩,可能會出現(xiàn)二次登錄的情況卓囚;
另一個是在手機上登錄以后再在PC上同樣訪問服務(wù)端數(shù)據(jù),Session能否共享就決定了客戶端是否要再次登錄诅病。

針對這兩種情況哪亿,目前都有理由的解決方案。

  • 多端共享Session
    多端共享Session必須要做的工作是不管是無線端還是PC端贤笆,后端的服務(wù)系統(tǒng)必須統(tǒng)一會話架構(gòu)蝇棉,也就是兩邊的登錄系統(tǒng)必須要基于一致的會員數(shù)據(jù)結(jié)構(gòu)、Cookie與Session的統(tǒng)一芥永。也就是不管是PC端登錄還是無線端登錄篡殷,后面對應(yīng)的數(shù)據(jù)結(jié)構(gòu)和存儲要統(tǒng)一,寫到客戶端的Cookie也必須一樣埋涧,這是前提條件板辽。

那么如何做到這一點?就是要按照我們在前面所說的實現(xiàn)分布式的Session框架棘催。


上面服務(wù)端統(tǒng)一Session后劲弦,在同一個終端上不管是訪問哪個服務(wù)端都能做到登錄狀態(tài)統(tǒng)一。例如不管是Native還是內(nèi)嵌Webview醇坝,都可以拿統(tǒng)一的Session ID去服務(wù)端驗證登錄狀態(tài)邑跪。

  • 多終端登錄
    目前很多網(wǎng)站都會出現(xiàn)無線端和PC端多端登錄的情況,例如可以通過掃碼登錄等呼猪。這些是如何實現(xiàn)的呢画畅?

    這里手機端在掃碼之前必須是已經(jīng)登錄的狀態(tài),因為這樣才能獲取到到底是誰將要登錄的信息宋距,同時掃碼的二維碼也帶有一個特定的標識轴踱,標識是這個客戶端
    通過手機端登陸了。當手機端掃碼成功后谚赎,會在服務(wù)端設(shè)置這個二維碼對應(yīng)的標識為已經(jīng)登錄成功寇僧,這時PC客戶端會通過將“心跳”請求發(fā)送到服務(wù)端摊腋,來驗證是否已經(jīng)登錄成功,這樣就稱為一種便捷的登錄方式嘁傀。(博主以微信掃碼登錄為例兴蒸,每次微信PC端的二維碼都是帶有一個唯一的標識,當你用登錄的手機微信掃碼之后细办,手機將你已登錄的微信信息獲取橙凳,并發(fā)送給微信服務(wù)端,微信服務(wù)端將二維碼的唯一標識以及手機微信的賬號信息綁定笑撞,發(fā)送給微信PC端岛啸,其中,微信PC二維碼客戶端類似Watch了某個ZK的節(jié)點進行監(jiān)聽茴肥,這樣避免客戶端每隔一段時間發(fā)送心跳)坚踩。

8 總結(jié)

Cookie和Session都是為了保持用戶訪問的連續(xù)狀態(tài),之所以要保持這種狀態(tài)瓤狐,一方面是為了方便業(yè)務(wù)實現(xiàn)瞬铸,另一方面就是簡化服務(wù)端的程序設(shè)計,提高訪問性能础锐,但是也帶來了安全問題嗓节、應(yīng)用的分布式部署帶來的Session的同步問題以及跨域名Session的同步問題(通過單點登錄避免)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末皆警,一起剝皮案震驚了整個濱河市拦宣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌信姓,老刑警劉巖鸵隧,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異意推,居然都是意外死亡掰派,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門左痢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來靡羡,“玉大人,你說我怎么就攤上這事俊性÷圆剑” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵定页,是天一觀的道長趟薄。 經(jīng)常有香客問我,道長典徊,這世上最難降的妖魔是什么杭煎? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任恩够,我火速辦了婚禮,結(jié)果婚禮上羡铲,老公的妹妹穿的比我還像新娘蜂桶。我一直安慰自己,他們只是感情好也切,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布扑媚。 她就那樣靜靜地躺著,像睡著了一般雷恃。 火紅的嫁衣襯著肌膚如雪疆股。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天倒槐,我揣著相機與錄音旬痹,去河邊找鬼。 笑死讨越,一個胖子當著我的面吹牛两残,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播谎痢,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼磕昼,長吁一口氣:“原來是場噩夢啊……” “哼卷雕!你這毒婦竟也來了节猿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤漫雕,失蹤者是張志新(化名)和其女友劉穎滨嘱,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浸间,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡太雨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了魁蒜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囊扳。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖兜看,靈堂內(nèi)的尸體忽然破棺而出锥咸,到底是詐尸還是另有隱情,我是刑警寧澤细移,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布搏予,位于F島的核電站,受9級特大地震影響弧轧,放射性物質(zhì)發(fā)生泄漏雪侥。R本人自食惡果不足惜碗殷,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望速缨。 院中可真熱鬧锌妻,春花似錦、人聲如沸鸟廓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽引谜。三九已至牍陌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間员咽,已是汗流浹背毒涧。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贝室,地道東北人契讲。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像滑频,于是被迫代替她去往敵國和親捡偏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 從三月份找實習到現(xiàn)在峡迷,面了一些公司银伟,掛了不少,但最終還是拿到小米绘搞、百度彤避、阿里、京東夯辖、新浪琉预、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,275評論 11 349
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蒿褂,服務(wù)發(fā)現(xiàn)圆米,斷路器,智...
    卡卡羅2017閱讀 134,701評論 18 139
  • 轉(zhuǎn)自 :http://blog.csdn.net/taoff/articles/1921009.aspx 一啄栓、術(shù)語...
    stone_yao閱讀 6,199評論 0 31
  • 這個城市娄帖,每到過年,花市就很熱鬧谴供,傳統(tǒng)一點的块茁,一定會買桔子,菊花,象征著來年大吉大利数焊∮捞剩花市里有各種各樣的花,...
    小小熊寶閱讀 327評論 1 0
  • 我們兄弟三個在小主人家住了下來佩耳,小主人很喜歡我們遂蛀,一有空就趴在籠子邊看我們,他現(xiàn)在敢抓我們了干厚,經(jīng)常抓著我的腰李滴,把我...
    蓮蕊添香閱讀 211評論 0 2