【JavaWeb】瞭解認證、授權、憑證、Cookie、Session、Token、JWT

一.什麼是認證(Authentication)

  • 通俗地講就是 驗證當前用戶的身份,證明“你是你自己” (比如:你每天上下班打卡,都需要通過指紋打卡,當你的指紋和系統裏錄入的指紋相匹配時,就打卡成功)
  • 互聯網中的認證:
    • 用戶名密碼登錄
    • 郵箱發送登錄鏈接
    • 手機號接收驗證碼

只要你能收到郵箱/驗證碼,就默認你是賬號的主人

二.什麼是授權(Authorization)

  • 用戶授予第三方應用訪問該用戶某些資源的權限
    • 你在安裝手機應用的時候,APP 會詢問是否允許授予權限(訪問相冊、地理位置等權限)
    • 你在訪問微信小程序時,當登錄時,小程序會詢問是否允許授予權限(獲取暱稱、頭像、地區、性別等個人信息)
  • 實現授權的方式有:cookie、session、token、OAuth

三.什麼是憑證(Credentials)

實現認證和授權的前提是需要一種媒介(證書 來標記訪問者的身份

  • 在戰國時期,商鞅變法,發明了照身帖。照身帖由官府發放,是一塊打磨光滑細密的竹板,上面刻有持有人的頭像和籍貫信息。國人必須持有,如若沒有就被認爲是黑戶,或者間諜之類的。
  • 在現實生活中,每個人都會有一張專屬的身份證,是用於證明持有人身份的一種法定證件。通過身份證,我們可以辦理手機卡/銀行卡/個人貸款/交通出行等等,這就是認證的憑證
  • 在互聯網應用中,一般網站(如CSDN)會有兩種模式,遊客模式和登錄模式。遊客模式下,可以正常瀏覽網站上面的文章,一旦想要點贊/收藏/分享文章,就需要登錄或者註冊賬號。當用戶登錄成功後,服務器會給該用戶使用的瀏覽器頒發一個令牌(token),這個令牌用來表明你的身份,每次瀏覽器發送請求時會帶上這個令牌,就可以使用遊客模式下無法使用的功能。

四.Cookie

 洛:大爺,樓上322住的是馬冬梅家吧? 
 大爺:馬都什麼? 
 夏洛:馬冬梅。
 大爺:什麼都沒啊? 
 夏洛:馬冬梅啊。
 大爺:馬什麼沒?
 夏洛:行,大爺你先涼快着吧。

要了解cookie先要了解HTTP是無狀態的Web服務器,什麼是無狀態呢?

一次對話完成後下一次對話完全不知道上一次對話發生了什麼

  • 如果在Web服務器中只是用來管理靜態文件還好說,對方是誰並不重要,把文件從磁盤中讀取出來發出去即可。但是隨着網絡的不斷髮展,比如電商中的購物車只有記住了用戶的身份才能夠執行接下來的一系列動作。所以此時就需要我們無狀態的服務器記住一些事情。

1.什麼是Cookie

那麼Web服務器是如何記住一些事情呢?

  • 既然Web服務器記不住東西,那麼我們就在外部想辦法記住,相當於服務器給每個客戶端都貼上了一個小紙條。上面記錄了服務器給我們返回的一些信息。然後服務器看到這張小紙條就知道我們是誰了。
  • HTTP 是無狀態的協議(對於事務處理沒有記憶能力,每次客戶端和服務端會話完成時,服務端不會保存任何會話信息):每個請求都是完全獨立的,服務端無法確認當前訪問者的身份信息,無法分辨上一次的請求發送者和這一次的發送者是不是同一個人。所以服務器與瀏覽器爲了進行會話跟蹤(知道是誰在訪問我),就必須主動的去維護一個狀態,這個狀態用於告知服務端前後兩個請求是否來自同一瀏覽器。而這個狀態需要通過 cookie 或者 session 去實現。

  • cookie 存儲在客戶端: cookie 是服務器發送到用戶瀏覽器保存在本地的一小塊數據,它會在瀏覽器 下次向同一服務器再發起請求時 被攜帶併發送到服務器上。

  • cookie 是不可跨域的: 每個 cookie 都會綁定單一的域名,無法在別的域名下獲取使用一級域名和二級域名之間是允許共享使用的(靠的是 domain,下面會講)。

2.Cookie產生的過程

  • Cookie是由服務器產生的
  1. 瀏覽器第一次訪問服務端時,服務器此時肯定不知道他的身份,所以創建一個獨特的身份標識數據,格式爲key=value,放入到Set-Cookie字段裏,隨着響應報文發給瀏覽器
  2. 瀏覽器看到有Set-Cookie字段以後就知道這是服務器給的身份標識,於是就保存起來下次請求時會自動將此key=value值放入到Cookie字段中發給服務端。
  3. 服務端收到請求報文後,發現Cookie字段中有值,就能根據此值識別用戶的身份然後提供個性化的服務。

在這裏插入圖片描述

接下來我們用代碼演示一下服務器是如何生成Cookie

@RequestMapping("/testCookies")
public String cookies(HttpServletResponse response){
    response.addCookie(new Cookie("testUser","xxxx"));
    return "cookies";
}

1.首次訪問服務器時發送的請求 http://localhost:8005/testCookies,可以看到服務器返回的響應中有Set-Cookie字段。而裏面的key=value值正是我們服務器中設置的值。
在這裏插入圖片描述

2.再次刷新這個頁面可以看到在請求體中已經設置了Cookie字段,並且將我們的值也帶過去了。這樣服務器就能夠根據Cookie中的值記住我們的信息了。

在這裏插入圖片描述

3.Cookie存放的位置

Cookie是存放在瀏覽器中的

  1. 在計算機打開Chrome,在右上角,一次點擊更多圖標->設置
  2. 在底部,點擊高級
  3. 在隱私設置和安全性下方,點擊網站設置
    在這裏插入圖片描述
  4. 依次點擊Cookie->查看所有Cookie和網站數據

因此瀏覽器替我們管理了Cookie的數據,如果此時換成了Firefox等其他的瀏覽器,因爲Cookie剛纔是存儲在Chrome裏面的,所以服務器又蒙圈了,不知道你是誰,就會給Firefox再次貼上小紙條。

4.cookie 重要的屬性

屬性 說明
name=value 鍵值對,設置 Cookie 的名稱及相對應的值,都必須是字符串類型
 - 如果值爲Unicode 字符,需要爲字符編碼。
 - 如果值爲二進制數據,則需要使用BASE64 編碼
domain 指定 cookie所屬域名,默認是當前域名
path 指定 cookie 在哪個路徑(路由)下生效,默認是 ‘/’。 如果設置爲/abc,則只有/abc下的路由可以訪問到該 cookie,如:/abc/read
maxAge cookie 的失效時間,單位
 如果爲整數,則該 cookie 在 maxAge 秒後失效。
 如果爲負數,該 cookie 爲臨時 cookie ,關閉瀏覽器即失效,瀏覽器也不會以任何形式保存該 cookie 。
 如果爲0,表示刪除該 cookie 。默認爲 -1
 - 比 expires 好用。
expires 過期時間,在設置的某個時間點後該 cookie 就會失效。
 一般瀏覽器的 cookie 都是默認儲存的,當關閉瀏覽器結束這個會話的時候,這個 cookie 也就會被刪除
secure 該 cookie 是否僅被使用安全協議傳輸。安全協議有 HTTPS,SSL等,在網絡上傳輸數據之前先將數據加密。默認爲false。
 當 secure 值爲 true 時,cookie 在 HTTP 中是無效,在 HTTPS 中才有效。
httpOnly 如果給某個 cookie 設置了 httpOnly 屬性,則無法通過 JS 腳本 讀取到該 cookie 的信息,但還是能通過 Application 中手動修改 cookie,所以只是在一定程度上可以防止 XSS 攻擊,不是絕對的安全

4.1.path屬性使用

Path屬性可以指定 cookie 在哪個路徑(路由)下生效,默認是 ‘/’。

測試後臺設置爲cookie.setPath("/testCookies"),先訪問http://localhost:8005/testCookies,在訪問http://localhost:8005,左圖請求路徑與後臺setPath指定的路徑是一樣的,所以有cookie,而右邊不一樣,所以沒有Cookie, 說明可以指定 cookie 在哪個路徑(路由)下生效

在這裏插入圖片描述

4.2.domain屬性使用

**domain屬性可以指定 cookie所屬域名,默認是當前域名 **

設置爲cookie.setDomain("localhost"),先訪問http://localhost:8005/testCookies,在訪問http://172.16.42.81:8005/testCookies,看下圖左邊有Cookie,右邊沒有Cookie。說明可以指定 cookie 在哪個域名下生效
在這裏插入圖片描述

5.SessionStorage,LocalStorage

HTML5提供了兩種本地存儲的方式 sessionStorage 和 localStorage
在這裏插入圖片描述

五.Session

1.什麼是Session

  • session 是另一種記錄服務器和客戶端會話狀態的機制
  • session 是基於 cookie 實現的Session存儲在服務器端,客戶端只存儲SessionId
  • session機制比cookie安全,在一次會話中將重要信息保存在Session中,瀏覽器只記錄SessionId,且一個SessionId對應一次會話請求。

在這裏插入圖片描述

session 認證流程

  1. 用戶第一次請求服務器的時候,服務器根據用戶提交的相關信息,創建對應的Session
  2. 請求返回時將此Session的唯一標識信息SessionID返回給瀏覽器
  3. 瀏覽器接收到服務器返回的SessionID 信息後,會將此信息存入到 Cookie 中,同時 Cookie 記錄此SessionID屬於哪個域名
  4. 用戶第二次訪問服務器的時候,請求會自動判斷此域名下是否存在 Cookie 信息,如果存在自動將 Cookie 信息也發送給服務端,服務端會從 Cookie 中獲取SessionID,再根據SessionID查找對應的Session信息,如果沒有找到說明用戶沒有登錄或者登錄失效,如果找到 Session證明用戶已經登錄可執行後面操作。

根據以上流程可知,SessionID** 是**連接 Cookie 和 Session 的一道橋樑,大部分系統也是根據此原理來驗證用戶登錄狀態。

2.Session產生的過程

@RequestMapping("/testSession") 
@ResponseBody 
public String testSession(HttpSession session){
	session.setAttribute("testSession","this is my session"); 
    return "testSession"; 
} 
@RequestMapping("/testGetSession")
@ResponseBody
public String testGetSession(HttpSession session){
    Object testSession = session.getAttribute("testSession");
    return String.valueOf(testSession);
}

第一次請求服務器訪問http://localhost:8005/testSession響應頭中在Set-Cookie中返回一個SessionId。然後瀏覽器記住此SessionId下次訪問時可以帶着此SessionId,然後就能根據此SessionId找到存儲在服務端的信息了。
在這裏插入圖片描述
在訪問路徑http://localhost:8005/testGetSession,發現得到了我們上面存儲在Session中的信息。
在這裏插入圖片描述

那麼Session什麼時候過期呢?

  • 客戶端: 和Cookie過期一致,如果沒設置,默認是關了瀏覽器就沒了,即再打開瀏覽器的時候初次請求頭中是沒有SessionId了
  • 服務端: 服務端的過期是真的過期,即服務器端的Session存儲的數據結構多久不可用了,默認是30分鐘。

Session是如何被管理的?

  • Session的管理是在容器中被管理的,什麼是容器呢TomcatJetty等都是容器。

接下來我們拿最常用的Tomcat爲例來看下Tomcat是如何管理Session的。

在源碼ManageBasecreateSession方法是用來創建Session的。

@Override
    public Session createSession(String sessionId) {
		//首先判斷Session數量是不是到了最大值,最大Session數可以通過參數設置
        if ((maxActiveSessions >= 0) &&
                (getActiveSessions() >= maxActiveSessions)) {
            rejectedSessions++;
            throw new TooManyActiveSessionsException(
                    sm.getString("managerBase.createSession.ise"),
                    maxActiveSessions);
        }

     	// 重用或者創建一個新的Session對象,請注意在Tomcat中Session就是StandardSession
		// 它是HttpSession的具體實現類,而HttpSession是Servlet規範中定義的接口
        Session session = createEmptySession();

        // 初始化新Session的值
        session.setNew(true);
        session.setValid(true);
        session.setCreationTime(System.currentTimeMillis());
        // 設置Session過期時間是30分鐘
        session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
        String id = sessionId;
        if (id == null) {
        	//生成sessionId
            id = generateSessionId();
        }
        session.setId(id);// 這裏會將Session添加到ConcurrentHashMap中
        sessionCounter++;

		//將創建時間添加到LinkedList中,並且把最先添加的時間移除
		//主要還是方便清理過期Session
        SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);
        synchronized (sessionCreationTiming) {
            sessionCreationTiming.add(timing);
            sessionCreationTiming.poll();
        }
        return (session);

    }

到此我們明白了Session是如何創建出來的,創建出 來後Session會被保存到一個ConcurrentHashMap中可以看StandardSession類。

Session是存儲在Tomcat的容器中,如果後端機器是多臺的話,在多個機器間是無法共享Session的,此時可以使用Spring提供的分佈式Session的解決方案,是將Session放在了Redis中

六.Cookie 和 Session 的區別

  • 安全性: Session 比 Cookie 安全,Session 是存儲在服務器端的,Cookie 是存儲在客戶端的
  • 存取值的類型不同:Cookie 只支持存字符串數據,想要設置其他類型的數據,需要將其轉換成字符串,Session 可以存任意數據類型
  • 有效期不同: Cookie 可設置爲長時間保持,比如我們經常使用的默認登錄功能,Session 一般失效時間較短,客戶端關閉(默認情況下)或者 Session 超時都會失效。
  • 存儲大小不同: 單個 Cookie 保存的數據不能超過 4K,Session 可存儲數據遠高於 Cookie,但是當訪問量過多,會佔用過多的服務器資源。

七.什麼是 Token(令牌)

1.Acesss Token

  • 訪問資源接口(API)時所需要的資源憑證

  • 簡單 token 的組成: uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,token 的前幾位以哈希算法壓縮成的一定長度的十六進制字符串)

  • 特點:

    • 服務端無狀態化、可擴展性好
    • 支持移動端設備
    • 安全
    • 支持跨程序調用
  • token 的身份驗證流程
    在這裏插入圖片描述

  1. 客戶端使用用戶名跟密碼請求登錄
  2. 服務端收到請求,去驗證用戶名與密碼
  3. 驗證成功後,服務端會簽發一個 token 並把這個 token 發送給客戶端
  4. 客戶端收到 token 以後,會把它存儲起來,比如放在 cookie 裏或者 localStorage 裏
  5. 客戶端每次向服務端請求資源的時候需要帶着服務端簽發的 token
  6. 服務端收到請求,然後去驗證客戶端請求裏面帶着的 token ,如果驗證成功,就向客戶端返回請求的數據

  • 每一次請求都需要攜帶 token,需要把 token 放到 HTTP 的 Header 裏
  • 基於 token 的用戶認證是一種服務端無狀態的認證方式,服務端不用存放 token 數據。用解析 token 的
  • 計算時間換取 session 的存儲空間,從而減輕服務器的壓力,減少頻繁的查詢數據庫
    token 完全由應用管理,所以它可以避開同源策略

總的來說就是客戶端在首次登陸以後,服務端再次接收http請求的時候,就只認token了,請求只要每次把token帶上就行了,服務器端會攔截所有的請求,然後校驗token的合法性,合法就放行,不合法就返回401(鑑權失敗)

2.Refresh Token

  • 另外一種 token——refresh token
  • refresh token 是專用於刷新 access token 的 token。如果沒有 refresh token,也可以刷新 access token,但每次刷新都要用戶輸入登錄用戶名與密碼,會很麻煩。有了 refresh token,可以減少這個麻煩,客戶端直接用 refresh token 去更新 access token,無需用戶進行額外的操作。

在這裏插入圖片描述

  • Access Token 的有效期比較短,當 Acesss Token 由於過期而失效時,使用 Refresh Token 就可以獲取到新的 Token,如果 Refresh Token 也失效了,用戶就只能重新登錄了。
  • Refresh Token 及過期時間是存儲在服務器的數據庫中,只有在申請新的 Acesss Token 時纔會驗證,不會對業務接口響應時間造成影響,也不需要向 Session 一樣一直保持在內存中以應對大量的請求。

八.Token 和 Session 的區別

  • Session 是一種記錄服務器和客戶端會話狀態的機制,使服務端有狀態化,可以記錄會話信息。而 Token 是令牌訪問資源接口(API)時所需要的資源憑證。Token 使服務端無狀態化,不會存儲會話信息。
  • Session 和 Token 並不矛盾,作爲身份認證 Token 安全性比 Session 好,因爲每一個請求都有簽名還能防止監聽以及重放攻擊,而 Session 就必須依賴鏈路層來保障通訊安全了。如果你需要實現有狀態的會話,仍然可以增加 Session 來在服務器端保存一些狀態。
  • 所謂 Session 認證只是簡單的把 User 信息存儲到 Session 裏,因爲 SessionID 的不可預測性,暫且認爲是安全的。而 Token ,如果指的是 OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對用戶,授權是針對 App 。其目的是讓某 App 有權利訪問某用戶的信息。這裏的 Token 是唯一的。不可以轉移到其它 App上,也不可以轉到其它用戶上。Session 只提供一種簡單的認證,即只要有此 SessionID ,即認爲有此 User 的全部權利。是需要嚴格保密的,這個數據應該只保存在站方,不應該共享給其它網站或者第三方 App。所以簡單來說:如果你的用戶數據可能需要和第三方共享,或者允許第三方調用 API 接口,用 Token 。如果永遠只是自己的網站,自己的 App,用什麼就無所謂了。

九.什麼是 JWT

  • JSON Web Token(簡稱 JWT)是目前最流行的跨域認證解決方案。
  • 是一種認證授權機制。
  • JWT 是爲了在網絡應用環境間傳遞聲明而執行的一種基於 JSON 的開放標準(RFC 7519)。JWT 的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源。比如用在用戶登錄上。
  • 可以使用 HMAC 算法或者是 RSA 的公/私祕鑰對 JWT 進行簽名。因爲數字簽名的存在,這些傳遞的信息是可信的。
  • 阮一峯老師的 JSON Web Token 入門教程 講的非常通俗易懂,這裏就不再班門弄斧了

生成 JWT
https://www.jsonwebtoken.io/
https://jwt.io/

1.JWT 的原理

在這裏插入圖片描述
JWT 認證流程:

  1. 用戶輸入用戶名/密碼登錄,服務端認證成功後,會返回給客戶端一個 JWT
  2. 客戶端將 token 保存到本地(通常使用 localstorage,也可以使用 cookie)
  3. 當用戶希望訪問一個受保護的路由或者資源的時候,需要請求頭的 Authorization 字段中使用Bearer 模式添加 JWT,其內容看起來是下面這樣
    Authorization: Bearer <token>
    
  • 服務端的保護路由將會檢查請求頭 Authorization 中的 JWT 信息,如果合法,則允許用戶的行爲
  • 因爲 JWT 是自包含的(內部包含了一些會話信息),因此減少了需要查詢數據庫的需要
  • 因爲 JWT 並不使用 Cookie 的,所以你可以使用任何域名提供你的 API 服務而不需要擔心跨域資源共享問題(CORS)
  • 因爲用戶的狀態不再存儲在服務端的內存中,所以這是一種無狀態的認證機制

2.JWT 的使用方式

客戶端收到服務器返回的 JWT,可以儲存在 Cookie 裏面,也可以儲存在 localStorage。


2.1.方式1

  • 當用戶希望訪問一個受保護的路由或者資源的時候,可以把它放在 Cookie 裏面自動發送,但是這樣不能跨域,所以更好的做法是放在 HTTP 請求頭信息的 Authorization 字段裏,使用 Bearer 模式添加 JWT。
GET /calendar/v1/events
Host: api.example.com
Authorization: Bearer <token>
  • 用戶的狀態不會存儲在服務端的內存中,這是一種 無狀態的認證機制
  • 服務端的保護路由將會檢查請求頭 Authorization 中的 JWT 信息,如果合法,則允許用戶的行爲。
  • 由於 JWT 是自包含的,因此減少了需要查詢數據庫的需要
  • JWT 的這些特性使得我們可以完全依賴其無狀態的特性提供數據 API 服務,甚至是創建一個下載流服務。
  • 因爲 JWT 並不使用 Cookie ,所以你可以使用任何域名提供你的 API 服務而不需要擔心跨域資源共享問題(CORS)

2.2.方式2

  • 跨域的時候,可以把 JWT 放在 POST 請求的數據體裏。

2.3.方式3

  • 通過 URL 傳輸
http://www.example.com/user?token=xxx

十.Token 和 JWT 的區別

相同:

  • 都是訪問資源的令牌
  • 都可以記錄用戶的信息
  • 都是使服務端無狀態化
  • 都是隻有驗證成功後,客戶端才能訪問服務端上受保護的資源

區別:

  • Token: 服務端驗證客戶端發送過來的 Token 時,還需要查詢數據庫獲取用戶信息,然後驗證 Token 是否有效。
  • JWT: 將 Token 和 Payload 加密後存儲於客戶端,服務端只需要使用密鑰解密進行校驗(校驗也是 JWT 自己實現的)即可,不需要查詢或者減少查詢數據庫,因爲 JWT 自包含了用戶信息和加密的數據。

十一.常見的前後端鑑權方式

  1. Session-Cookie
  2. Token 驗證(包括 JWT,SSO)
  3. OAuth2.0(開放授權)

前後端常見的幾種鑑權方式

十二.常見的加密算法

在這裏插入圖片描述

  • 哈希算法(Hash Algorithm)又稱散列算法、散列函數、哈希函數,是一種從任何一種數據中創建小的數字“指紋”的方法。哈希算法將數據重新打亂混合,重新創建一個哈希值。
  • 哈希算法主要用來保障數據真實性(即完整性),即發信人將原始消息和哈希值一起發送,收信人通過相同的哈希函數來校驗原始數據是否真實。
  • 哈希算法通常有以下幾個特點:
    • 正像快速:原始數據可以快速計算出哈希值
    • 逆向困難:通過哈希值基本不可能推導出原始數據
    • 輸入敏感:原始數據只要有一點變動,得到的哈希值差別很大
    • 衝突避免:很難找到不同的原始數據得到相同的哈希值,宇宙中原子數大約在 10 的 60 次方到 80 次方之間,所以 2 的 256 次方有足夠的空間容納所有的可能,算法好的情況下衝突碰撞的概率很低:
      • 2 的 128 次方爲 340282366920938463463374607431768211456,也就是 10 的 39 次方級別
      • 2 的 160 次方爲 1.4615016373309029182036848327163e+48,也就是 10 的 48 次方級別
      • 2 的 256 次方爲 1.1579208923731619542357098500869 × 10 的 77 次方,也就是 10 的 77 次方

注意:

  • 以上不能保證數據被惡意篡改,原始數據和哈希值都可能被惡意篡改,要保證不被篡改,可以使用RSA 公鑰私鑰方案,再配合哈希值。
  • 哈希算法主要用來防止計算機傳輸過程中的錯誤,早期計算機通過前 7 位數據第 8 位奇偶校驗碼來保障(12.5% 的浪費效率低),對於一段數據或文件,通過哈希算法生成 128bit 或者 256bit 的哈希值,如果校驗有問題就要求重傳。

十三.常見問題

1.使用 cookie 時需要考慮的問題

  • 因爲存儲在客戶端,容易被客戶端篡改,使用前需要驗證合法性
  • 不要存儲敏感數據,比如用戶密碼,賬戶餘額
  • 使用 httpOnly 在一定程度上提高安全性
  • 儘量減少 cookie 的體積,能存儲的數據量不能超過 4kb
  • 設置正確的 domain 和 path,減少數據傳輸
  • cookie 無法跨域
  • 一個瀏覽器針對一個網站最多存 20 個Cookie,瀏覽器一般只允許存放 300 個Cookie
  • 移動端對 cookie 的支持不是很好,而 session 需要基於 cookie 實現,所以移動端常用的是 token

2.使用 session 時需要考慮的問題

  • 將 session 存儲在服務器裏面,當用戶同時在線量比較多時,這些 session 會佔據較多的內存,需要在服務端定期的去清理過期的 session
  • 當網站採用集羣部署的時候,會遇到多臺 web 服務器之間如何做 session 共享的問題。因爲 session 是由單個服務器創建的,但是處理用戶請求的服務器不一定是那個創建 session 的服務器,那麼該服務器就無法拿到之前已經放入到 session 中的登錄憑證之類的信息了。
  • 當多個應用要共享 session 時,除了以上問題,還會遇到跨域問題,因爲不同的應用可能部署的主機不一樣,需要在各個應用做好 cookie 跨域的處理。
  • sessionId 是存儲在 cookie 中的,假如瀏覽器禁止 cookie 或不支持 cookie 怎麼辦? 一般會把 sessionId 跟在 url 參數後面即重寫 url,所以 session 不一定非得需要靠 cookie 實現
  • 移動端對 cookie 的支持不是很好,而 session 需要基於 cookie 實現,所以移動端常用的是 token

3.使用 token 時需要考慮的問題

  • 如果你認爲用數據庫來存儲 token 會導致查詢時間太長,可以選擇放在內存當中。比如 redis 很適合你對 token 查詢的需求。
  • token 完全由應用管理,所以它可以避開同源策略
  • token 可以避免 CSRF 攻擊(因爲不需要 cookie 了)
  • 移動端對 cookie 的支持不是很好,而 session 需要基於 cookie 實現,所以移動端常用的是 token

4.使用 JWT 時需要考慮的問題

  • 因爲 JWT 並不依賴 Cookie 的,所以你可以使用任何域名提供你的 API 服務而不需要擔心跨域資源共享問題(CORS)
  • JWT 默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。
  • JWT 不加密的情況下,不能將祕密數據寫入 JWT。
  • JWT 不僅可以用於認證,也可以用於交換信息。有效使用 JWT,可以降低服務器查詢數據庫的次數。
  • JWT 最大的優勢是服務器不再需要存儲 Session,使得服務器認證鑑權業務可以方便擴展。但這也是 - - JWT 最大的缺點:由於服務器不需要存儲 Session 狀態,因此使用過程中無法廢棄某個 Token 或者更改 Token 的權限。也就是說一旦 JWT 簽發了,到期之前就會始終有效,除非服務器部署額外的邏輯。
  • JWT 本身包含了認證信息,一旦泄露,任何人都可以獲得該令牌的所有權限。爲了減少盜用,JWT的有效期應該設置得比較短。對於一些比較重要的權限,使用時應該再次對用戶進行認證。
  • JWT 適合一次性的命令認證,頒發一個有效期極短的 JWT,即使暴露了危險也很小,由於每次操作都會生成新的 JWT,因此也沒必要保存 JWT,真正實現無狀態。
  • 爲了減少盜用,JWT 不應該使用 HTTP 協議明碼傳輸,要使用 HTTPS 協議傳輸。

十四.使用加密算法時需要考慮的問題

  • 絕不要以明文存儲密碼
  • 永遠使用 哈希算法 來處理密碼,絕不要使用 Base64 或其他編碼方式來存儲密碼,這和以明文存儲密碼是一樣的,使用哈希,而不要使用編碼。 編碼以及加密,都是雙向的過程,而密碼是保密的,應該只被它的所有者知道, 這個過程必須是單向的。哈希正是用於做這個的,從來沒有解哈希這種說法, 但是編碼就存在解碼,加密就存在解密。
  • 絕不要使用弱哈希或已被破解的哈希算法,像 MD5 或 SHA1 ,只使用強密碼哈希算法。
  • 絕不要以明文形式顯示或發送密碼,即使是對密碼的所有者也應該這樣。如果你需要 “忘記密碼” 的功能,可以隨機生成一個新的一次性的(這點很重要)密碼,然後把這個密碼發送給用戶。

十五.分佈式架構下 session 共享方案

1.session 複製

任何一個服務器上的 session 發生改變(增刪改),該節點會把這個 session 的所有內容序列化,然後廣播給所有其它節點,不管其他服務器需不需要 session ,以此來保證 session 同步

  • 優點: 可容錯,各個服務器間 session 能夠實時響應。
  • 缺點: 會對網絡負荷造成一定壓力,如果 session 量大的話可能會造成網絡堵塞,拖慢服務器性能。

2.粘性 session /IP 綁定策略

採用 Ngnix 中的 ip_hash 機制,將某個 ip的所有請求都定向到同一臺服務器上,即將用戶與服務器綁定。 用戶第一次請求時,負載均衡器將用戶的請求轉發到了 A 服務器上,如果負載均衡器設置了粘性 session 的話,那麼用戶以後的每次請求都會轉發到 A 服務器上,相當於把用戶和 A 服務器粘到了一塊,這就是粘性 session 機制。

  • 優點: 簡單,不需要對 session 做任何處理。
  • 缺點: 缺乏容錯性,如果當前訪問的服務器發生故障,用戶被轉移到第二個服務器上時,他的 session 信息都將失效。
  • 適用場景: 發生故障對客戶產生的影響較小;服務器發生故障是低概率事件。
  • 實現方式: 以 Nginx 爲例,在 upstream 模塊配置 ip_hash 屬性即可實現粘性 session。

3.session 共享(常用)

  • 使用分佈式緩存方案比如 Memcached 、Redis 來緩存 session,但是要求 Memcached 或 Redis 必須是集羣
  • 把 session 放到 Redis 中存儲,雖然架構上變得複雜,並且需要多訪問一次 Redis ,但是這種方案帶來的好處也是很大的:
    • 實現了 session 共享;
    • 可以水平擴展(增加 Redis 服務器);
    • 服務器重啓 session 不丟失(不過也要注意 session 在 Redis 中的刷新/失效機制);
    • 不僅可以跨服務器 session 共享,甚至可以跨平臺(例如網頁端和 APP 端)

在這裏插入圖片描述

4.session 持久化

將 session 存儲到 數據庫 中,保證 session 的持久化

  • 優點: 服務器出現問題,session 不會丟失
  • 缺點: 如果網站的訪問量很大,把 session 存儲到數據庫中,會對數據庫造成很大壓力,還需要增加額外的開銷維護數據庫。

只要關閉瀏覽器 ,session 真的就消失了?

  • 不對。對 session 來說,除非程序通知服務器刪除一個 session,否則服務器會一直保留,程序一般都是在用戶做登出的時候發個指令去刪除 session。

  • 然而瀏覽器從來不會主動在關閉之前通知服務器它將要關閉,因此服務器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分 session 機制都使用會話 cookie 來保存 session id,而關閉瀏覽器後這個 session id 就消失了,再次連接服務器時也就無法找到原來的 session。如果服務器設置的 cookie 被保存在硬盤上,或者使用某種手段改寫瀏覽器發出的 HTTP 請求頭,把原來的 session id 發送給服務器,則再次打開瀏覽器仍然能夠打開原來的 session。

  • 恰恰是由於關閉瀏覽器不會導致 session 被刪除,迫使服務器爲 session 設置了一個失效時間,當距離客戶端上一次使用 session 的時間超過這個失效時間時,服務器就認爲客戶端已經停止了活動,纔會把 session 刪除以節省存儲空間。


參考以下文章
詳解 Cookie,Session,Token
一文徹底搞懂Cookie、Session、Token到底是什麼
徹底瞭解Cookie、Session、Token到底是什麼
前端鑑權

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