http協議是無狀態協議,服務端不能從請求中判斷用戶的身份,用戶怎么每次去找到自己對應的資訊呢?
1. cookie
這種方式最簡單,在用戶第一次登陸成功某個網站A,網站A服務端就將你的用戶資訊(比如用戶名,用戶id,證件號等等)寫入到cookie 物件中,然后再把這個cookie物件發送給對應的客戶端,客戶端就存下這個cookie,例如博客園的cookie如下

當cookie超時時間到了瀏覽器就會自動洗掉這個cookie,這個時候需要你重新登錄一下, 然后服務器就會根據你的用戶名和密碼去資料庫中查詢一次,成功查詢到就再一次將用戶資訊丟到cookie物件中,回傳給客戶端存起來,后續每次請求都帶著這個cookie
這種方式的好處就是:用戶的所有資訊都存在客戶端,服務端只有在資料庫中存了一份,服務端壓力很小;
壞處是顯而易見,每次都要帶上這個cookie這么多資訊,一方面是傳輸效率問題,另一方面是安全問題,別人只要截獲你的cookie,你的所有資訊都一覽無余;
還有一點就是有的客戶端會禁用cookie...

2. session
在cookie的基礎上優化了一下,因為不是有安全和效率問題嗎,那么我們就把用戶所有的資訊都存到服務端,例如現在有這樣的一個結構:Map<sessionId,Session<User>>
用戶第一次登陸成功,就會生成一個唯一字串sessionId,然后將sessionId和用戶資訊存到map中,最后就將這個sessionId丟到cookie回傳給客戶端,后續的客戶端訪問服務端只需要帶著cookie,服務端就能從cookie中獲取到這個sessionId,到Map里面去找,就可以找到用戶資訊了;
注意,不一定非要叫做sessionId這個名字啊,叫做aId,bId等等也行....看每個地方的要求
這種方式比較安全,而且效率也提高了,因為只需要多傳一個字串,但是服務端記憶體中存所有的用戶資訊,壓力都給到了服務端
我們還從請求方式來比較cookie和session:
cookie的方式一般只能用戶post請求,因為get請求的url有長度限制
session的方式只是get和post方式,get方式的話在url后面添加一個引數傳sessionId就行了,即使客戶端禁用了cookie,在服務端將sessionId傳給了客戶端之后,客戶端想辦法存起來下次請求的時候帶過去就行了

3. session共享
上面說的是單體應用的實作方式,但是到了分布式環境下就會失效(很多東西在單機中使用是可以的,分布式環境下就沒用了,比如資料庫事務,鎖),下圖所示,會導致tomcat2需要用戶重新登錄

解決方案有兩種:
1)hash一致性:在nginx中配置ip_hash,其實就是用過一定的演算法對用戶的ip處理,假如用戶第一次訪問的是tomcat1,那么只要用戶ip不會變化,第二次該用戶訪問的還是tomcat1
2)引入中間件:這里以redis為例

4. jwt
上面的實作方式看著一大堆東西也是麻煩,又是傳sessionId,又是引入redis,在分布式環境下有沒有簡單的方式啊!
jwt全稱JSON Web Token,我們之前每次都是傳的sessionId,這個字串是沒有實際意義的,只是起到了一個唯一標識的作用,那么有沒有可能我們把它的語意化呢?就是想辦法直接決議這個字串,然后可以獲取用戶資訊
下圖所示,結構是不是一下子簡單多了,可以看到只要我們每次請求都帶上這個token,不管是單機環境,還是分布式環境都適用,而且服務端也不需要保存什么東西,客戶端只需要保存一個token字串就行了;

現在就比較關心的是jwt的那個演算法和生成后的token字串有什么特殊的要求!
token字串的格式,分為三部分,用點進行連接:aaa.bbb.ccc
示例:

第一部分是Header:放入token的型別(“JWT”)和演算法名稱(比如:HMAC SHA256或者RSA等等),然后使用Base64對這個JSON編碼就得到JWT的第一部分

第二部分是Payload:一般放入用戶的不敏感資訊,比如用戶id,名稱和角色等,即使被別人截獲了也沒啥用,然后使用Base64對這個JSON編碼就得到JWT的第二部分

第三部分是Signature:準備一個只有你自己知道的密鑰,加上第一部分的字串aaa和第二部分的字串,通過Header中宣告的演算法就生成了簽名,也就得到了第三部分

將上面三部分通過點相連就組成了token,然后發到客戶端,客戶端只需要每次在請求頭中放入這個token,后端通過密鑰驗證這個token的合法性,并且從Payload中獲取用戶不敏感的資訊,進行后續處理
想看看簡單的demo,可以看看這個老哥的博客 ,不過一般校驗jwt是配置一個攔截器進行處理的
5. jwt的補充
其實仔細想了想,一般還有以下兩個疑問
1)Token被盜了怎么辦?
答: 在啟用https的情況下,token被放在Header中還是比較安全的,另外Token的有效期不要設定過長,例如可以設定為1小時(微信公眾號的網頁開發的Token有效期為2小時),
2)Token到期了如何處理?
答:理論上Token過期應該是跳到登錄界面,但這樣太不友好了,可以在后臺根據Token的過期時間定期去請求新的Token,
可以看看以下兩篇博客看看
應用JWT進行用戶認證及Token的重繪
JWT生成token及過期處理方案
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/261608.html
標籤:Java
