一問帶你區分清楚Authentication,Authorization以及Cookie、Session、Token

Guide哥發表於2019-09-29

上週寫了一個 適合初學者入門 Spring Security With JWT 的 Demo 。Demo 地址:github.com/Snailclimb/… 。很多人可能對許可權認證領域一些常見的概念都不是特別瞭解,所以寫了篇文章專門介紹一下這些概念。文中對於每一部分知識點可能有推薦的文章,閱讀原文即可看到文章的連結。

1. 認證 (Authentication) 和授權 (Authorization)的區別是什麼?

這是一個絕大多數人都會混淆的問題。首先先從讀音上來認識這兩個名詞,很多人都會把它倆的讀音搞混,所以我建議你先先去查一查這兩個單詞到底該怎麼讀,他們的具體含義是什麼。

說簡單點就是:

  • 認證 (Authentication): 你是誰。
  • 授權 (Authorization): 你有許可權幹什麼。

稍微正式點(囉嗦點)的說法就是:

  • Authentication(認證) 是驗證您的身份的憑據(例如使用者名稱/使用者ID和密碼),通過這個憑據,系統得以知道你就是你,也就是說系統存在你這個使用者。所以,Authentication 被稱為身份/使用者驗證。
  • Authorization(授權) 發生在 **Authentication(認證)**之後。授權嘛,光看意思大家應該就明白,它主要掌管我們訪問系統的許可權。比如有些特定資源只能具有特定許可權的人才能訪問比如admin,有些對系統資源操作比如刪除、新增、更新只能特定人才具有。

這兩個一般在我們的系統中被結合在一起使用,目的就是為了保護我們系統的安全性。

2. 什麼是Cookie ? Cookie的作用是什麼?如何在服務端使用 Cookie ?

2.1 什麼是Cookie ? Cookie的作用是什麼?

Cookie 和 Session都是用來跟蹤瀏覽器使用者身份的會話方式,但是兩者的應用場景不太一樣。

維基百科是這樣定義 Cookie 的:Cookies是某些網站為了辨別使用者身份而儲存在使用者本地終端上的資料(通常經過加密)。簡單來說: Cookie 存放在客戶端,一般用來儲存使用者資訊

下面是 Cookie 的一些應用案例:

  1. 我們在 Cookie 中儲存已經登入過得使用者資訊,下次訪問網站的時候頁面可以自動幫你登入的一些基本資訊給填了。除此之外,Cookie 還能儲存使用者首選項,主題和其他設定資訊。
  2. 使用Cookie 儲存 session 或者 token ,向後端傳送請求的時候帶上 Cookie,這樣後端就能取到session或者token了。這樣就能記錄使用者當前的狀態了,因為 HTTP 協議是無狀態的。
  3. Cookie 還可以用來記錄和分析使用者行為。舉個簡單的例子你在網上購物的時候,因為HTTP協議是沒有狀態的,如果伺服器想要獲取你在某個頁面的停留狀態或者看了哪些商品,一種常用的實現方式就是將這些資訊存放在Cookie

2.2 如何能在 服務端使用 Cookie 呢?

這部分內容參考:attacomsian.com/blog/cookie… Boot中使用Cookie 的內容可以檢視這篇文章。

1)設定cookie返回給客戶端

@GetMapping("/change-username")
public String setCookie(HttpServletResponse response) {
    // 建立一個 cookie
    Cookie cookie = new Cookie("username", "Jovan");
    //設定 cookie過期時間
    cookie.setMaxAge(7 * 24 * 60 * 60); // expires in 7 days
    //新增到 response 中
    response.addCookie(cookie);

    return "Username is changed!";
}
複製程式碼

2) 使用Spring框架提供的@CookieValue註解獲取特定的 cookie的值

@GetMapping("/")
public String readCookie(@CookieValue(value = "username", defaultValue = "Atta") String username) {
    return "Hey! My username is " + username;
}
複製程式碼

3) 讀取所有的 Cookie 值

@GetMapping("/all-cookies")
public String readAllCookies(HttpServletRequest request) {

    Cookie[] cookies = request.getCookies();
    if (cookies != null) {
        return Arrays.stream(cookies)
                .map(c -> c.getName() + "=" + c.getValue()).collect(Collectors.joining(", "));
    }

    return "No cookies";
}
複製程式碼

3. Cookie 和 Session 有什麼區別?如何使用Session進行身份驗證?

Session 的主要作用就是通過服務端記錄使用者的狀態。 典型的場景是購物車,當你要新增商品到購物車的時候,系統不知道是哪個使用者操作的,因為 HTTP 協議是無狀態的。服務端給特定的使用者建立特定的 Session 之後就可以標識這個使用者並且跟蹤這個使用者了。

Cookie 資料儲存在客戶端(瀏覽器端),Session 資料儲存在伺服器端。相對來說 Session 安全性更高。如果使用 Cookie 的一些敏感資訊不要寫入 Cookie 中,最好能將 Cookie 資訊加密然後使用到的時候再去伺服器端解密。

那麼,如何使用Session進行身份驗證?

很多時候我們都是通過 SessionID 來實現特定的使用者,SessionID 一般會選擇存放在 Redis 中。舉個例子:使用者成功登陸系統,然後返回給客戶端具有 SessionID 的 Cookie,當使用者向後端發起請求的時候會把 SessionID 帶上,這樣後端就知道你的身份狀態了。關於這種認證方式更詳細的過程如下:

Session Based Authentication flow

  1. 使用者向伺服器傳送使用者名稱和密碼用於登陸系統。
  2. 伺服器驗證通過後,伺服器為使用者建立一個 Session,並將 Session資訊儲存 起來。
  3. 伺服器向使用者返回一個 SessionID,寫入使用者的 Cookie。
  4. 當使用者保持登入狀態時,Cookie 將與每個後續請求一起被髮送出去。
  5. 伺服器可以將儲存在 Cookie 上的 Session ID 與儲存在記憶體中或者資料庫中的 Session 資訊進行比較,以驗證使用者的身份,返回給使用者客戶端響應資訊的時候會附帶使用者當前的狀態。

另外,Spring Session提供了一種跨多個應用程式或例項管理使用者會話資訊的機制。如果想詳細瞭解可以檢視下面幾篇很不錯的文章:

4. 什麼是 Token?什麼是 JWT?如何基於Token進行身份驗證?

我們在上一個問題中探討了使用 Session 來鑑別使用者的身份,並且給出了幾個 Spring Session 的案例分享。 我們知道 Session 資訊需要儲存一份在伺服器端。這種方式會帶來一些麻煩,比如需要我們保證儲存 Session 資訊伺服器的可用性、不適合移動端(依賴Cookie)等等。

有沒有一種不需要自己存放 Session 資訊就能實現身份驗證的方式呢?使用 Token 即可!JWT (JSON Web Token) 就是這種方式的實現,通過這種方式伺服器端就不需要儲存 Session 資料了,只用在客戶端儲存服務端返回給客戶的 Token 就可以了,擴充套件性得到提升。

JWT 本質上就一段簽名的 JSON 格式的資料。由於它是帶有簽名的,因此接收者便可以驗證它的真實性。

下面是 RFC 7519 對 JWT 做的較為正式的定義。

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. ——JSON Web Token (JWT)

JWT 由 3 部分構成:

  1. Header :描述 JWT 的後設資料。定義了生成簽名的演算法以及 Token 的型別。
  2. Payload(負載):用來存放實際需要傳遞的資料
  3. Signature(簽名):伺服器通過PayloadHeader和一個金鑰(secret)使用 Header 裡面指定的簽名演算法(預設是 HMAC SHA256)生成。

在基於 Token 進行身份驗證的的應用程式中,伺服器通過PayloadHeader和一個金鑰(secret)建立令牌(Token)並將 Token 傳送給客戶端,客戶端將 Token 儲存在 Cookie 或者 localStorage 裡面,以後客戶端發出的所有請求都會攜帶這個令牌。你可以把它放在 Cookie 裡面自動傳送,但是這樣不能跨域,所以更好的做法是放在 HTTP Header 的 Authorization欄位中:Authorization: Bearer Token

Token Based Authentication flow

  1. 使用者向伺服器傳送使用者名稱和密碼用於登陸系統。
  2. 身份驗證服務響應並返回了簽名的 JWT,上面包含了使用者是誰的內容。
  3. 使用者以後每次向後端發請求都在Header中帶上 JWT。
  4. 服務端檢查 JWT 並從中獲取使用者相關資訊。

推薦閱讀:

5 什麼是OAuth 2.0?

OAuth 是一個行業的標準授權協議,主要用來授權第三方應用獲取有限的許可權。而 OAuth 2.0是對 OAuth 1.0 的完全重新設計,OAuth 2.0更快,更容易實現,OAuth 1.0 已經被廢棄。詳情請見:rfc6749

實際上它就是一種授權機制,它的最終目的是為第三方應用頒發一個有時效性的令牌 token,使得第三方應用能夠通過該令牌獲取相關的資源。

OAuth 2.0 比較常用的場景就是第三方登入,當你的網站接入了第三方登入的時候一般就是使用的 OAuth 2.0 協議。

推薦閱讀:

參考

公眾號

如果大家想要實時關注我更新的文章以及分享的乾貨的話,可以關注我的公眾號。

《Java面試突擊》: 由本文件衍生的專為面試而生的《Java面試突擊》V2.0 PDF 版本公眾號後臺回覆 "Java面試突擊" 即可免費領取!

Java工程師必備學習資源: 一些Java工程師常用學習資源公眾號後臺回覆關鍵字 “1” 即可免費無套路獲取。

我的公眾號

相關文章