在我們的 java 業務系統中,或多或少的會涉及到權限、認證等類似的概念。
但是很多小伙伴還是傻傻的分不清這些的概念和區別,今天我們就來好好的捋一捋,將其區別的概念深深的刻在腦海中。
認證 Authentication
百度百科中對於認證的解釋是:身份驗證(Authentication),
在 .NET Framework 安全中,通過對照某些機構檢查用戶的憑據,發現和驗證主體標識的過程。
當然,今天我們來討論肯定不會用這么生硬的詞來解釋的。
- 通俗地講就是 驗證當前用戶的身份,證明“你是你自己”(比如:你每天上下班打卡,都需要通過指紋打卡,當你的指紋和系統里錄入的指紋相匹配時,就打卡成功)
常見的認證方式:
- 用戶名密碼登錄
- 郵箱發送登錄鏈接
- 手機號接收驗證碼
- 只要你能收到郵箱/驗證碼,就默認你是賬號的主人
授權 Authorization
所謂授權,就是某個用戶授予其他應用訪問該用戶某些資源的權限。
例如,在你安裝手機應用的時候,APP肯定會跳出來問是否允許授予權限(訪問相冊、位置等權限);
你在訪問微信小程序時,當登錄時,小程序會詢問是否允許授予權限(獲取昵稱、頭像、地區、性別等個人信息)
實現授權的方式有:cookie、session、token、OAuth
憑證 Credentials
實現認證和授權的前提是需要一種媒介(證書) 來標記訪問者的身份。
這個其實很好理解,身份證大家肯定是都有的。過身份證,我們可以辦理手機卡/銀行卡/個人貸款/交通出行等等,這就是認證的憑證。
在互聯網應用中,一般網站會有兩種模式,游客模式和登錄模式。
- 游客模式下,可以正常瀏覽網站上面的文章,一旦想要點贊/收藏/分享文章,就需要登錄或者注冊賬號。
- 登錄模式,當用戶登錄成功后,服務器會給該用戶使用的瀏覽器頒發一個令牌(token),這個令牌用來表明你的身份,每次瀏覽器發送請求時會帶上這個令牌,就可以使用游客模式下無法使用的功能。
Cookie
HTTP 是無狀態的協議(對於事務處理沒有記憶能力,每次客戶端和服務端會話完成時,服務端不會保存任何會話信息):
每個請求都是完全獨立的,服務端無法確認當前訪問者的身份信息,無法分辨上一次的請求發送者和這一次的發送者是不是同一個人。
所以服務器與瀏覽器為了進行會話跟蹤(知道是誰在訪問我),就必須主動的去維護一個狀態,這個狀態用於告知服務端前后兩個請求是否來自同一瀏覽器。而這個狀態需要通過 cookie 或者 session 去實現。
cookie 存儲在客戶端:cookie 是服務器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶並發送到服務器上。
cookie 是不可跨域的:每個 cookie 都會綁定單一的域名,無法在別的域名下獲取使用,一級域名和二級域名之間是允許共享使用的(靠的是 domain)。
Session
session 是另外一種記錄服務器和客戶端會話狀態的機制,通常情況下,session 是基於 cookie 實現的,session 存儲在服務器端,sessionId 會被存儲到客戶端的cookie 中
session 認證流程:
- 用戶第一次請求服務器的時候,服務器根據用戶提交的相關信息,創建對應的 Session
- 請求返回時將此 Session 的唯一標識信息 SessionID 返回給瀏覽器
- 瀏覽器接收到服務器返回的 SessionID 信息后,會將此信息存入到 Cookie 中,同時 Cookie 記錄此 SessionID 屬於哪個域名
- 當用戶第二次訪問服務器的時候,請求會自動判斷此域名下是否存在 Cookie 信息,如果存在自動將 Cookie 信息也發送給服務端,服務端會從 Cookie 中獲取 SessionID,再根據 SessionID 查找對應的 Session 信息,如果沒有找到說明用戶沒有登錄或者登錄失效,如果找到 Session 證明用戶已經登錄可執行后面操作。
目前,大部分系統都是根據此原理來驗證用戶的登錄狀態的。
Cookie 和 Session 的區別
這個應該是面試中問的頻率非常高的一個問題了。
- 安全性:Session 比 Cookie 安全,Session 是存儲在服務器端的,Cookie 是存儲在客戶端的。
- 存取值的類型不同:Cookie 只支持存字符串數據,想要設置其他類型的數據,需要將其轉換成字符串,Session 可以存任意數據類型。
- 有效期不同:Cookie 可設置為長時間保持,比如我們經常使用的默認登錄功能,Session 一般失效時間較短,客戶端關閉(默認情況下)或者 Session 超時都會失效。
- 存儲大小不同:單個 Cookie 保存的數據不能超過 4K,Session 可存儲數據遠高於 Cookie,但是當訪問量過多,會占用過多的服務器資源。
令牌 Token
Acesss Token
訪問資源接口(API)時所需要的資源憑證,簡單 token 的組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,token 的前幾位以哈希算法壓縮成的一定長度的十六進制字符串)
Acesss Token的特點是 * 服務端無狀態化、可擴展性好 * 支持移動端設備 * 安全 * 支持跨程序調用
token 的身份驗證流程如下:
- 客戶端使用用戶名跟密碼請求登錄
- 服務端收到請求,去驗證用戶名與密碼
- 驗證成功后,服務端會簽發一個 token 並把這個 token 發送給客戶端
- 客戶端收到 token 以后,會把它存儲起來,比如放在 cookie 里或者 localStorage 里
- 客戶端每次向服務端請求資源的時候需要帶着服務端簽發的 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)
JSON Web Token(簡稱 JWT)是目前最流行的跨域認證解決方案
JWT 是為了在網絡應用環境間傳遞聲明而執行的一種基於 JSON 的開放標准(RFC 7519)。JWT 的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源。比如用在用戶登錄上。
可以使用 HMAC 算法或者是 RSA 的公/私秘鑰對 JWT 進行簽名。因為數字簽名的存在,這些傳遞的信息是可信的。
JWT 認證流程:
- 用戶輸入用戶名/密碼登錄,服務端認證成功后,會返回給客戶端一個 JWT
- 客戶端將 token 保存到本地(通常使用 localstorage,也可以使用 cookie)
- 當用戶希望訪問一個受保護的路由或者資源的時候,需要請求頭的 Authorization 字段中使用Bearer 模式添加 JWT,其內容看起來是下面這樣