什麼是認證(Authentication)
通俗地講就是驗證當前用戶的身份什麼是授權(Authorization)
用戶授予第三方應用訪問該用戶某些資源的權限 你在安裝手機應用的時候,APP 會詢問是否允許授予權限(訪問相冊、地理位置等權限) 你在訪問微信小程序時,當登錄時,小程序會詢問是否允許授予權限(獲取暱稱、頭像、地區、性別等個人信息)實現授權的方式有:cookie、session、token、OAuth什麼是憑證(Credentials)
實現認證和授權的前提是需要一種媒介(證書) 來標記訪問者的身份 在戰國時期,商鞅變法,發明了照身帖。照身帖由官府發放,是一塊打磨光滑細密的竹板,上面刻有持有人的頭像和籍貫信息。國人必須持有,如若沒有就被認為是黑戶,或者間諜之類的。 在現實生活中,每個人都會有一張專屬的居民身份證,是用於證明持有人身份的一種法定證件。通過身份證,我們可以辦理手機卡/銀行卡/個人貸款/交通出行等等,這就是什麼是 Cookie
HTTP 是無狀態的協議(對於事務處理沒有記憶能力,每次客戶端和服務端會話完成時,服務端不會保存任何會話信息):每個請求都是完全獨立的,服務端無法確認當前訪問者的身份信息,無法分辨上一次的請求發送者和這一次的發送者是不是同一個人。所以服務器與瀏覽器為了進行會話跟蹤(知道是誰在訪問我),就必須主動的去維護一個狀態,這個狀態用於告知服務端前後兩個請求是否來自同一瀏覽器。而這個狀態需要通過 cookie 或者 session 去實現。cookie 存儲在客戶端: cookie 是服務器發送到用戶瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一服務器再發起請求時被攜帶併發送到服務器上。cookie 重要的屬性
什麼是 Session
session 是另一種記錄服務器和客戶端會話狀態的機制session 是基於 cookie 實現的,session 存儲在服務器端,sessionId 會被存儲到客戶端的cookie 中根據以上流程可知,SessionID 是連接 Cookie 和 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 的前幾位以哈希算法壓縮成的一定長度的十六進制字符串)特點: 服務端無狀態化、可擴展性好 支持移動端設備 安全 支持跨程序調用token 的身份驗證流程:Refresh Token
另外一種 token——refresh tokenrefresh token 是專用於刷新 access token 的 token。如果沒有 refresh token,也可以刷新 access token,但每次刷新都要用戶輸入登錄用戶名與密碼,會很麻煩。有了 refresh token,可以減少這個麻煩,客戶端直接用 refresh token 去更新 access token,無需用戶進行額外的操作。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
jwt.io/
www.jsonwebtoken.io/
JWT 的原理
<code>Authorization: Bearer <token>
複製代碼/<token>/<code>服務端的保護路由將會檢查請求頭 Authorization 中的 JWT 信息,如果合法,則允許用戶的行為因為 JWT 是自包含的(內部包含了一些會話信息),因此減少了需要查詢數據庫的需要因為 JWT 並不使用 Cookie 的,所以你可以使用任何域名提供你的 API 服務而不需要擔心跨域資源共享問題(CORS)因為用戶的狀態不再存儲在服務端的內存中,所以這是一種無狀態的認證機制
JWT 的使用方式
客戶端收到服務器返回的 JWT,可以儲存在 Cookie 裡面,也可以儲存在 localStorage。方式一
當用戶希望訪問一個受保護的路由或者資源的時候,可以把它放在 Cookie 裡面自動發送,但是這樣不能跨域,所以更好的做法是放在 HTTP 請求頭信息的 Authorization 字段裡,使用 Bearer 模式添加 JWT。 GET /calendar/v1/events Host: api.example.com Authorization: Bearer <token> 複製代碼 用戶的狀態不會存儲在服務端的內存中,這是一種方式二
跨域的時候,可以把 JWT 放在 POST 請求的數據體裡。方式三
通過 URL 傳輸<code>http://www.example.com/user?token=xxx
複製代碼/<code>
項目中使用 JWT
項目地址
https://github.com/yjdjiayou/jwt-demo
Token 和 JWT 的區別
相同:
區別:
Token:服務端驗證客戶端發送過來的 Token 時,還需要查詢數據庫獲取用戶信息,然後驗證 Token 是否有效。JWT: 將 Token 和 Payload 加密後存儲於客戶端,服務端只需要使用密鑰解密進行校驗(校驗也是 JWT 自己實現的)即可,不需要查詢或者減少查詢數據庫,因為 JWT 自包含了用戶信息和加密的數據。常見的前後端鑑權方式
Session-CookieToken 驗證(包括 JWT,SSO)OAuth2.0(開放授權)常見的加密算法
注意:
以上不能保證數據被惡意篡改,原始數據和哈希值都可能被惡意篡改,要保證不被篡改,可以使用RSA 公鑰私鑰方案,再配合哈希值。哈希算法主要用來防止計算機傳輸過程中的錯誤,早期計算機通過前 7 位數據第 8 位奇偶校驗碼來保障(12.5% 的浪費效率低),對於一段數據或文件,通過哈希算法生成 128bit 或者 256bit 的哈希值,如果校驗有問題就要求重傳。常見問題
使用 cookie 時需要考慮的問題
因為存儲在客戶端,容易被客戶端篡改,使用前需要驗證合法性不要存儲敏感數據,比如用戶密碼,賬戶餘額使用 httpOnly 在一定程度上提高安全性儘量減少 cookie 的體積,能存儲的數據量不能超過 4kb設置正確的 domain 和 path,減少數據傳輸cookie 無法跨域一個瀏覽器針對一個網站最多存 20 個Cookie,瀏覽器一般只允許存放 300 個Cookie移動端對 cookie 的支持不是很好,而 session 需要基於 cookie 實現,所以移動端常用的是 token使用 session 時需要考慮的問題
將 session 存儲在服務器裡面,當用戶同時在線量比較多時,這些 session 會佔據較多的內存,需要在服務端定期的去清理過期的 session當網站採用集群部署的時候,會遇到多臺 web 服務器之間如何做 session 共享的問題。因為 session 是由單個服務器創建的,但是處理用戶請求的服務器不一定是那個創建 session 的服務器,那麼該服務器就無法拿到之前已經放入到 session 中的登錄憑證之類的信息了。當多個應用要共享 session 時,除了以上問題,還會遇到跨域問題,因為不同的應用可能部署的主機不一樣,需要在各個應用做好 cookie 跨域的處理。使用 token 時需要考慮的問題
如果你認為用數據庫來存儲 token 會導致查詢時間太長,可以選擇放在內存當中。比如 redis 很適合你對 token 查詢的需求。token 完全由應用管理,所以它可以避開同源策略token 可以避免 CSRF 攻擊(因為不需要 cookie 了)移動端對 cookie 的支持不是很好,而 session 需要基於 cookie 實現,所以移動端常用的是 token使用 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 信息都將失效。 適用場景: 發生故障對客戶產生的影響較小;服務器發生故障是低概率事件 。 實現方式:
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,否則服務器會一直保留,程序一般都是在用戶做 log off 的時候發個指令去刪除 session。然而瀏覽器從來不會主動在關閉之前通知服務器它將要關閉,因此服務器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分 session 機制都使用會話 cookie 來保存 session id,而關閉瀏覽器後這個 session id 就消失了,再次連接服務器時也就無法找到原來的 session。如果服務器設置的 cookie 被保存在硬盤上,或者使用某種手段改寫瀏覽器發出的 HTTP 請求頭,把原來的 session id 發送給服務器,則再次打開瀏覽器仍然能夠打開原來的 session。恰恰是
項目地址
在項目中使用 JWT