1), Http Basic Auth
- Http Basic Auth 簡單點說明就是每次請求API時都提供用戶的 username 和 password ,簡而言之,Basic Auth 是配合 RESTful API 使用的最簡單的認證機制,只需提供用戶名密碼即可,但由於有把用戶名密碼暴露給第三方客戶端的風險,在生產環境下被使用的越來越少。
- 因此,在開發對外的RESTful API 時,儘量避免採用HTTP Basic Auth 。
2),Cookie Auth
- Cookie 認證機制就是爲一次請求認證在服務端創建一個 Session 對象,同時在客戶端的瀏覽器創建了一個 Cookie 對象。
- 通過客戶端帶上來 Cookie 對象來與服務器端的 Session 對象匹配來實現狀態管理的。
- 默認的,當我們關閉瀏覽器的時候,Cookie 會被刪除。 但是可以通過修改 Cookie 的 expire 使 cookie 在一定時間內有效。
3), OAuth -第三方認證登錄
- OAuth (開放授權) 是一個開放的授權標準,允許用戶讓第三方應用訪問改用戶在某一 web 服務上存儲的私密的資源(如,照片,視屏,聯繫人列表等),而無需將用戶名和密碼提供給第三方應用。
- OAuth 允許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每一個令牌授權一個特定的第三方系統(如,視屏編輯網站)在特定的時段(如,接下來2個小時內)訪問特定的資源(如,僅僅是某一相冊中的視頻)。這樣,OAuth 讓用戶可以授權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非所有內容
- 這種基於 OAuth 的認證機制適用於個人消費者類的互聯網產品,如社交類APP等應用,但是不太適合自由認證權限管理的企業應用。
4),Token Auth
- 使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概流程是:
- 客戶端使用用戶名和密碼請求登錄
- 服務端收到登錄請求,去驗證用戶名與密碼
- 驗證成功後,服務端會簽發一個 Token ,再把這個Token 發送給客戶端
- 客戶端收到 Token 以後把它存儲起來,比如說放在 Cookie 裏
- 客戶端每次向服務端請求資源的時候帶着服務端簽發的Token
- 服務端收到請求後,然後驗證客戶端請求裏面帶着的Token,如果驗證成功,就向客戶端返回請求的數據
Token Auth 的有點
Token機制相對於Cookie機制又有什麼好處呢?
- 支持跨域訪問 : Cookie 是不允許跨域訪問的,這一點對 Token 機制是不存在的,前提是傳輸的用戶認證信息是通過HTTP頭傳輸
- 無狀態(也稱爲:服務端可擴展行) : Token 機制在服務端不需要存儲session 信息,因爲Token 自身包含了所有登錄用戶的信息,只需要在客戶端cookie或本地介質存儲狀態信息。
- 更適合CDN : 可以通過內容分發網絡請求你服務端的所有資料(如 javascript,HTML,圖片等)而你的服務端只需要提供API即可。
- 去耦 : 不需要綁定到一個特定的身份驗證方案。Token 可以在任何地方生成,只要在你的API被調用的時候,你可以進行Token生成即可。
- 更適合於移動應用 : 當你客戶端是一個原生平臺(IOS , Android ,Windows 等)時,Cookie 是不被支持的(你需要通過Cookie容器進行處理),這時採用Token 認證機制就會簡單的多。
- CSRF : 因爲不在依賴與Cookie ,所以你就不需要開率對 CSRF(跨站請求僞造)的防範。
- 性能 : 一次網絡往返時間(通過數據庫查詢session信息)總比做一次 HMACSHA256 計算的 Token 驗證和解析要費時得多。
- 不需要爲登錄頁面做特殊處理 : 如果你使用Protractor 做功能測試的時候,不需要爲登錄頁面做特殊處理。
- 基於標準化 : 你的API 可以採用標準化的 JSON Web Token (JWT) 這個標準已經存在多個後端庫(.NET , Ruby , Java ,PHP)和多家公司的支持(如Firebase ,google , microsoft)
5),基於JWT 的Token 認證機制實現
5-1), 什麼是JWT
- Json Web Token (JWT) 是一個非常輕巧的規範。 這個規範允許我們使用 JWT 在用戶和服務器之間傳遞安全可靠的信息。
5-2),JWT 組成
- 一個 JWT 實際上就是一個字符串 ,它由三部分組成 , 頭部 , 載荷 和 簽名 。
5-2-1),頭部 (Header)
- 頭部用於描述關於該 JWT 的最基本的信息,例如 其類型以及簽名所用的算法等。 這也可以被表示成一個 JSON 對象。
{"typ":"JWT","alg":"HS256"}
- 在頭部指明瞭簽名算法是 HS256 算法。我們進行 BASE64 編碼 ,編碼後的字符串爲 https://base64.supfree.net/
JTdCJTIydHlwJTIyJTNBJTIySldUJTIyJTJDJTIyYWxnJTIyJTNBJTIySFMyNTYlMjIlN0Q=
注意
- Base64 是一種基於 64 個可打印字符串來表示二進制數據的表示方法。由於2的6次方等於64,所以每6個比特爲一個單元,對應某個可打印字符。三個字節有24個比特,對應於4個Base64單元,即 3個字節需要用4個可打印字符來表示。 JDK 中提供了非常方便的 BASE64Encoder 和 BASE64Decoder ,用它們可以非常方便的完成基於Base64的編碼和解碼。
5-2-2),載荷 (plyload)
- 載荷就是存放有效信息的地方。這個名字像是特指飛機上承載的貨品,這些有效信息包含三個部分:
(1),標準中註冊聲明(建議但不強制使用)
iss: jwt簽發者
sub: jwt所面向的用戶
aud: 接收jwt的一方
exp: jwt的過期時間,這個過期時間必須要大於簽發時間
nbf: 定義在什麼時間之前,該jwt都是不可用的.
iat: jwt的簽發時間
jti: jwt的唯一身份標識,主要用來作爲一次性token,從而回避重放攻擊。
(2),公共的聲明
- 公共的聲明可以添加任何的信息,一般添加用戶的相關信息或業務需要的必要信息,但不建議添加敏感信息,因爲該部分在客戶端可解密。
(3)私有的聲明
- 私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因爲 base64 是對稱解密的,意味着該部分信息可以歸類爲明文信息。
- 這個指的就是自定義的 claim 比如前面那個結構舉例中的 admin 和 name 都屬於自定義的 claim 。這些 claim 跟JWT 標準規定的 claim 區別在於 : JWT 規定的 claim ,JWT 的接收方在拿到JWT之後,都知道怎麼對這些標準 claim 進行驗證(還不知道是否能夠驗證),而parivate claims不會去驗證,除非明確告訴接收方要對這些 claim 進行驗證以及規則纔行。
定義一個 載荷(payload)
{"sub":"1234567890","name":"John Doe","admin":true}
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
5-2-3),簽證 signature
- JWT 的第三部分是一個簽證信息,這個簽證信息由三部分組成 header(base64後) , payload(base64後) 和 secret(鹽值)
這個部分需要base64 加密後的header 和 base64 加密後的payload使用,連接組成字符串,然後通過 header 中聲明的加密方式進行加鹽secret組成加密,然後就構成了 jwt 的第三部分。
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
將這三部分用.連接成一個完成的字符串,構成了最終的jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6I kpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7Hg Q
注意
- secret 是保存在服務端的,jwt 的簽發生成也是在服務端的, secret 就是用來進行jwt 的簽發 和 jwt 的驗證 ,所以它就是你服務器的私鑰,任何場景都不應該流露出去,一旦客戶端得知這個secret ,那就意味着客戶端可以自我簽發 JWT了。