你們好,我是 Guide哥!端午已過,又要開始工做學習啦!html
我發現有不少小夥伴對認證受權方面的知識不是特別瞭解,搞不清 Session 認證、JWT 以及 Cookie 這些概念。前端
因此,根據我根據平常對這部分學習已經在項目中的實際運用總結了這 13 個相關的問題而且附上了詳細的回答。但願可以對你們有幫助!java
這是一個絕大多數人都會混淆的問題。首先先從讀音上來認識這兩個名詞,不少人都會把它倆的讀音搞混,因此我建議你先先去查一查這兩個單詞到底該怎麼讀,他們的具體含義是什麼。git
說簡單點就是:github
稍微正式點(囉嗦點)的說法就是 :面試
認證 :redis
受權:算法
這兩個通常在咱們的系統中被結合在一塊兒使用,目的就是爲了保護咱們系統的安全性。spring
系統權限控制最常採用的訪問控制模型就是 RBAC 模型 。數據庫
什麼是 RBAC 呢?
RBAC 即基於角色的權限訪問控制(Role-Based Access Control)。這是一種經過角色關聯權限,角色同時又關聯用戶的受權的方式。
簡單地說:一個用戶能夠擁有若干角色,每個角色有能夠被分配若干權限這樣,就構形成「用戶-角色-權限」 的受權模型。在這種模型中,用戶與角色、角色與權限之間構成了多對多的關係,以下圖
在 RBAC 中,權限與角色相關聯,用戶經過成爲適當角色的成員而獲得這些角色的權限。這就極大地簡化了權限的管理。
一般 RBAC 下的權限設計相關的表有5 張,其中有 2 張用於創建表之間的聯繫:
經過這個權限模型,咱們能夠建立不一樣的角色併爲不一樣的角色分配不一樣的權限範圍(菜單)。
一般來講,若是系統對於權限控制要求比較嚴格的話,通常都會選擇使用 RBAC 模型來作權限控制。
Cookie
和 Session
都是用來跟蹤瀏覽器用戶身份的會話方式,可是二者的應用場景不太同樣。
維基百科是這樣定義 Cookie
的:
Cookies
是某些網站爲了辨別用戶身份而儲存在用戶本地終端上的數據(一般通過加密)。
簡單來講: Cookie
存放在客戶端,通常用來保存用戶信息。
下面是 Cookie
的一些應用案例:
Cookie
中保存已經登陸過的用戶信息,下次訪問網站的時候頁面能夠自動幫你登陸的一些基本信息給填了。除此以外,Cookie
還能保存用戶首選項,主題和其餘設置信息。Cookie
保存 Session
或者 Token
,向後端發送請求的時候帶上 Cookie
,這樣後端就能取到 Session
或者 Token
了。這樣就能記錄用戶當前的狀態了,由於 HTTP 協議是無狀態的。Cookie
還能夠用來記錄和分析用戶行爲。舉個簡單的例子你在網上購物的時候,由於 HTTP 協議是沒有狀態的,若是服務器想要獲取你在某個頁面的停留狀態或者看了哪些商品,一種經常使用的實現方式就是將這些信息存放在 Cookie
我這裏以 Spring Boot 項目爲例。
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";
}
複製代碼
更多關於如何在 Spring Boot 中使用 Cookie
的內容能夠查看這篇文章:How to use cookies in Spring Boot 。
Session
的主要做用就是經過服務端記錄用戶的狀態。 典型的場景是購物車,當你要添加商品到購物車的時候,系統不知道是哪一個用戶操做的,由於 HTTP 協議是無狀態的。服務端給特定的用戶建立特定的 Session
以後就能夠標識這個用戶而且跟蹤這個用戶了。
Cookie
數據保存在客戶端(瀏覽器端),Session
數據保存在服務器端。相對來講 Session
安全性更高。爲了保證 Cookie
中信息的安全性,最好能將 Cookie
信息加密而後使用到的時候再去服務器端解密。
那麼,如何使用 Session
進行身份驗證?
不少時候咱們都是經過 SessionID
來實現特定的用戶,SessionID
通常會選擇存放在 Redis 中。舉個例子:
SessionID
的 Cookie
SessionID
帶上,這樣後端就知道你的身份狀態了。關於這種認證方式更詳細的過程以下:
Session
,並將 Session
信息存儲起來。SessionID
,寫入用戶的 Cookie
。Cookie
將與每一個後續請求一塊兒被髮送出去。Cookie
上的 SessionID
與存儲在內存中或者數據庫中的 Session
信息進行比較,以驗證用戶的身份,返回給用戶客戶端響應信息的時候會附帶用戶當前的狀態。使用 Session
的時候須要注意下面幾個點:
Session
的關鍵業務必定要確保客戶端開啓了 Cookie
。Session
的過時時間。另外,Spring Session 提供了一種跨多個應用程序或實例管理用戶會話信息的機制。若是想詳細瞭解能夠查看下面幾篇很不錯的文章:
Session-Cookie 方案在單體環境是一個很是好的身份認證方案。可是,當服務器水平拓展成多節點時,Session-Cookie 方案就要面臨挑戰了。
舉個例子:假如咱們部署了兩份相同的服務 A,B,用戶第一次登錄的時候 ,Nginx 經過負載均衡機制將用戶請求轉發到 A 服務器,此時用戶的 Session 信息保存在 A 服務器。結果,用戶第二次訪問的時候 Nginx 將請求路由到 B 服務器,因爲 B 服務器沒有保存 用戶的 Session 信息,致使用戶須要從新進行登錄。
咱們應該如何避免上面這種狀況的出現呢?
有幾個方案可供你們參考:
這是一道經典的面試題!
通常是經過 Cookie
來保存 SessionID
,假如你使用了 Cookie
保存 SessionID
的方案的話, 若是客戶端禁用了 Cookie
,那麼 Session
就沒法正常工做。
可是,並非沒有 Cookie
以後就不能用 Session
了,好比你能夠將 SessionID
放在請求的 url
裏面https://javaguide.cn/?Session_id=xxx
。這種方案的話可行,可是安全性和用戶體驗感下降。固然,爲了你也能夠對 SessionID
進行一次加密以後再傳入後端。
CSRF (Cross Site Request Forgery)通常被翻譯爲 跨站請求僞造 。那麼什麼是 跨站請求僞造 呢?說簡單用你的身份去發送一些對你不友好的請求。舉個簡單的例子:
小壯登陸了某網上銀行,他來到了網上銀行的帖子區,看到一個帖子下面有一個連接寫着「科學理財,年盈利率過萬」,小壯好奇的點開了這個連接,結果發現本身的帳戶少了 10000 元。這是這麼回事呢?原來黑客在連接中藏了一個請求,這個請求直接利用小壯的身份給銀行發送了一個轉帳請求,也就是經過你的 Cookie 向銀行發出請求。
<a src=http://www.mybank.com/Transfer?bankId=11&money=10000>科學理財,年盈利率過萬</>
複製代碼
上面也提到過,進行 Session
認證的時候,咱們通常使用 Cookie
來存儲 SessionId
,當咱們登錄後後端生成一個 SessionId
放在 Cookie 中返回給客戶端,服務端經過 Redis 或者其餘存儲工具記錄保存着這個 SessionId
,客戶端登陸之後每次請求都會帶上這個 SessionId
,服務端經過這個 SessionId
來標示你這我的。若是別人經過 Cookie
拿到了 SessionId
後就能夠代替你的身份訪問系統了。
Session
認證中 Cookie
中的 SessionId
是由瀏覽器發送到服務端的,藉助這個特性,攻擊者就能夠經過讓用戶誤點攻擊連接,達到攻擊效果。
可是,咱們使用 Token
的話就不會存在這個問題,在咱們登陸成功得到 Token
以後,通常會選擇存放在 localStorage
(瀏覽器本地存儲)中。而後咱們在前端經過某些方式會給每一個發到後端的請求加上這個 Token
,這樣就不會出現 CSRF 漏洞的問題。由於,即便有個你點擊了非法連接發送了請求到服務端,這個非法請求是不會攜帶 Token
的,因此這個請求將是非法的。
須要注意的是不管是 Cookie
仍是 Token
都沒法避免 跨站腳本攻擊(Cross Site Scripting)XSS 。
跨站腳本攻擊(Cross Site Scripting)縮寫爲 CSS 但這會與層疊樣式表(Cascading Style Sheets,CSS)的縮寫混淆。所以,有人將跨站腳本攻擊縮寫爲 XSS。
XSS 中攻擊者會用各類方式將惡意代碼注入到其餘用戶的頁面中。就能夠經過腳本盜用信息好比 Cookie
。
推薦閱讀:如何防止 CSRF 攻擊?—美團技術團隊
咱們在前面的問題中探討了使用 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 部分構成:
Token
的類型。Payload
、Header
和一個密鑰(secret
)使用 Header
裏面指定的簽名算法(默認是 HMAC SHA256)生成。在基於 Token 進行身份驗證的的應用程序中,服務器經過Payload
、Header
和一個密鑰(secret
)建立令牌(Token
)並將 Token
發送給客戶端,客戶端將 Token
保存在 Cookie 或者 localStorage 裏面,之後客戶端發出的全部請求都會攜帶這個令牌。你能夠把它放在 Cookie 裏面自動發送,可是這樣不能跨域,因此更好的作法是放在 HTTP Header 的 Authorization 字段中:Authorization: Bearer Token
。
Header
中帶上 JWT。SSO(Single Sign On)即單點登陸說的是用戶登錄多個子系統的其中一個就有權訪問與其相關的其餘系統。舉個例子咱們在登錄了京東金融以後,咱們同時也成功登錄京東的京東超市、京東國際、京東生鮮等子系統。
OAuth 是一個行業的標準受權協議,主要用來受權第三方應用獲取有限的權限。而 OAuth 2.0 是對 OAuth 1.0 的徹底從新設計,OAuth 2.0 更快,更容易實現,OAuth 1.0 已經被廢棄。詳情請見:rfc6749。
實際上它就是一種受權機制,它的最終目的是爲第三方應用頒發一個有時效性的令牌 Token,使得第三方應用可以經過該令牌獲取相關的資源。
OAuth 2.0 比較經常使用的場景就是第三方登陸,當你的網站接入了第三方登陸的時候通常就是使用的 OAuth 2.0 協議。
另外,如今 OAuth 2.0 也常見於支付場景(微信支付、支付寶支付)和開發平臺(微信開放平臺、阿里開放平臺等等)。
微信支付帳戶相關參數:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yqIC91bs-1623925796543)(./images/basis-of-authority-certification/微信支付-fnglfdlgdfj.png)]
下圖是 Slack OAuth 2.0 第三方登陸的示意圖:
推薦閱讀:
花了半個月寫的最新版 Java學習路線已近更新!多是你看過最用心、最全面的 Java 後端學習路線。
我是 Guide哥,擁抱開源,喜歡烹飪。開源項目 JavaGuide 做者,Github:Snailclimb - Overview 。將來幾年,但願持續完善 JavaGuide,爭取可以幫助更多學習 Java 的小夥伴!共勉!凎!點擊查看個人2020年工做彙報!
原創不易,歡迎點贊分享,歡迎關注 @JavaGuide,我會持續分享原創乾貨~
本回答爲我本人原創,如需轉載,還請註明出處啊!