常見登陸鑑權方案

編者注:今天咱們分享的是盧士傑同窗整理的網站經常使用鑑權方案的實現原理與實現以及他們的適用場景,幫助你們在業務中作合適的選擇。html

背景

提及鑑權你們應該都很熟悉,不過做爲前端開發來說,鑑權的流程大頭都在後端小哥那邊,本文的目的就是爲了讓你們瞭解一下常見的鑑權的方式和原理。前端

認知:HTTP 是一個無狀態協議,因此客戶端每次發出請求時,下一次請求沒法得知上一次請求所包含的狀態數據。mysql

1、HTTP Auth Authentication

簡介

HTTP 提供一個用於權限控制和認證的通用框架。最經常使用的HTTP認證方案是HTTP Basic Authenticationgit

鑑權流程

加解密過程

// Authorization 加密過程
let email = "postmail@test.com"
let password = "12345678"
let auth = `${email}:${password}`
const buf = Buffer.from(auth, 'ascii');
console.info(buf.toString('base64')); // cG9zdG1haWxAdGVzdC5jb206MTIzNDU2Nzg=

// Authorization 解密過程
const buf = Buffer.from(authorization.split(' ')[1] || ''),  'base64');
const user = buf.toString('ascii').split(':');

其餘 HTTP 認證

通用 HTTP 身份驗證框架有多個驗證方案使用。不一樣的驗證方案會在安全強度上有所不一樣。github

IANA 維護了一系列的驗證方案,除此以外還有其餘類型的驗證方案由虛擬主機服務提供,例如 Amazon AWS ,常見的驗證方案包括:redis

  • Basic (查看 RFC 7617, Base64 編碼憑證. 詳情請參閱下文.),
  • Bearer (查看 RFC 6750, bearer 令牌經過OAuth 2.0保護資源),
  • Digest (查看 RFC 7616, 只有 md5 散列 在Firefox中支持, 查看 bug 472823 用於SHA加密支持),
  • HOBA (查看 RFC 7486 (草案), HTTP Origin-Bound 認證, 基於數字簽名),
  • Mutual (查看 draft-ietf-httpauth-mutual),
  • AWS4-HMAC-SHA256 (查看 AWS docs)

2、Cookie + Session

註冊流程

思考:爲何要在密碼里加點「鹽」?sql

鑑權流程

Session 存儲

最經常使用的 Session 存儲方式是 KV 存儲,如Redis,在分佈式、API 支持、性能方面都是比較好的,除此以外還有 mysql、file 存儲。後端

若是服務是分佈式的,使用 file 存儲,多個服務間存在同步 session 的問題;高併發狀況下錯誤讀寫鎖的控制。安全

Session Refresh

咱們上面提到的流程中,缺乏 Session 的刷新的環節,咱們不能在用戶登陸以後通過一個 expires 時間就把用戶踢出去,若是在 Session 有效期間用戶一直在操做,這時候 expires 時間就應該刷新。服務器

以 Koa 爲例,刷新 Session 的機制也比較簡單:
開發一個 middleware(默認狀況下全部請求都會通過該 middleware),若是校驗 Session 有效,就更新 Session 的 expires: 當前時間+過時時間。

優化:

  1. 頻繁更新 session 會影響性能,能夠在 session 快過時的時候再更新過時時間。
  2. 若是某個用戶一直在操做,同一個 sessionID 可能會長期有效,若是相關 cookie 泄露,可能致使比較大的風險,能夠在生成 sessionID 的同時生成一個 refreshID,在 sessionID 過時以後使用 refreshID 請求服務端生成新的 sessionID(這個方案須要前端判斷 sessionID 失效,並攜帶 refreshID 發請求)。

單設備登陸

有些狀況下,只容許一個賬號在一個端下登陸,若是換了一個端,須要把以前登陸的端踢下線(默認狀況下,同一個賬號能夠在不一樣的端下同時登陸的)。

這時候能夠藉助一個服務保存用戶惟一標識和 sessionId 值的對應關係,若是同一個用戶,但 sessionId 不同,則不容許登陸或者把以前的踢下線(刪除舊 session )。

3、JWT

簡介

JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用於做爲JSON對象在各方之間安全地傳輸信息。該信息能夠被驗證和信任,由於它是數字簽名的。

JWT 組成

JWT 由三部分組成,分別是 header(頭部),payload(載荷),signature(簽證) 這三部分以小數點鏈接起來。

例如使用名爲 jwt-token 的cookie來存儲 JWT 例如:

jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0.WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8;

使用.分割值能夠獲得三部分組成元素,按照順序分別爲:

  • header

    • 值:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    • Base64 解碼: {"alg": "HS256", "type": "JWT"}
  • payload

    • 值:eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0
    • Base64 解碼:

      {
        "name": "lushijie", 
        "iat": 1532595255, // 發佈時間
        "exp": 1532595270 // 過時時間
      }
  • signature

    • 值:WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8
    • 解碼:

      const headerEncode = base64Encode(header);
      const payloadEncode = base64Encode(payload);
      let signature = HMACSHA256(headerEncode + '.' + payloadEncode, '密鑰');

鑑權流程

Token 校驗

對於驗證一個 JWT 是否有效也是比較簡單的,服務端根據前面介紹的計算方法計算出 signature,和要校驗的JWT中的 signature 部分進行對比就能夠了,若是 signature 部分相等則是一個有效的 JWT。

Token Refresh

爲了減小 JWT Token 泄露風險,通常有效期會設置的比較短。 這樣就會存在 JWT Token 過時的狀況,咱們不可能讓用戶頻繁去登陸獲取新的 JWT Token。

解決方案:

能夠同時生成 JWT Token 與 Refresh Token,其中 Refresh Roken 的有效時間長於 JWT Token,這樣當 JWT Token 過時以後,使用 Refresh Token 獲取新的 JWT Token 與 Refresh Token,其中 Refresh Token 只能使用一次。

4、OAuth

簡介

有時候,咱們登陸某個網站,但咱們又不想註冊該網站的帳號,這時咱們可使用第三方帳號登陸,好比 github、微博、微信、QQ等。

開放受權(OAuth)是一個開放標準,容許用戶讓第三方應用訪問該用戶在某一網站上存儲的私密的資源(如照片,視頻,聯繫人列表),而無需將用戶名和密碼提供給第三方應用。

OAuth容許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。每個令牌受權一個特定的網站(例如,視頻編輯網站)在特定的時段(例如,接下來的2小時內)內訪問特定的資源(例如僅僅是某一相冊中的視頻)。這樣,OAuth讓用戶能夠受權第三方網站訪問他們存儲在另外服務提供者的某些特定信息,而非全部內容。

OAuth是OpenID的一個補充,可是徹底不一樣的服務。

—— 摘自 維基百科

受權流程

名詞解釋:

  • Third-party application:第三方應用程序又稱"客戶端"(client),好比打開知乎,使用第三方登陸,選擇 Github 登陸,這時候知乎就是客戶端。
  • Resource Owner:資源全部者,本文中又稱"用戶"(user),即登陸用戶。
  • Authorization server:認證服務器,即 Github 專門用來處理認證的服務器。
  • Resource server:資源服務器,即 Github 存放用戶生成的資源的服務器。它與認證服務器,能夠是同一臺服務器,也能夠是不一樣的服務器。

  • A. A網站讓用戶跳轉到 GitHub,請求受權碼;GitHub 要求用戶登陸,而後詢問「知乎網站要求得到 xx 權限,你是否贊成?」;
  • B. 用戶贊成,GitHub 就會重定向回 A 網站,同時發回一個受權碼;
  • C. A 網站使用受權碼,向 GitHub 請求令牌;
  • D. GitHub 返回令牌;
  • E. A 網站使用令牌,向 GitHub 請求用戶數據;

其餘受權模式

受權碼模式(authorization code)是功能最完整、流程最嚴密的受權模式。除了咱們上面所說的受權碼模式,其實還有其餘受權模式:

  1. 簡化模式(Implicit grant type)
    有些 Web 應用是純前端應用,沒有後端。這時就不能用上面的方式了,必須將令牌儲存在前端。RFC 6749 就規定了第二種方式,容許直接向前端頒發令牌。這種方式沒有受權碼這個中間步驟
  2. 密碼模式(Resource Owner Password Credentials Grant)
    若是你高度信任某個應用,RFC 6749 也容許用戶把用戶名和密碼,直接告訴該應用。該應用就使用你的密碼,申請令牌
  3. 客戶端模式(Client Credentials Grant)
    適用於沒有前端的命令行應用,即在命令行下請求令牌

關於這些模式詳細請見:OAuth2.0 的四種方式

單點登陸

單點登陸(Single Sign On, SSO),即:單一標記(單點)登陸。例如:QQ,我在QQ空間登陸一次,我能夠去訪問QQ產品的其餘服務:QQ郵箱、騰訊新聞等,都能保證你的帳戶保持登陸狀態。

延伸閱讀:

5、總結對比

沒有最好,只有最合適!!!

  • HTTP Auth Authentication:

    • 梳理總結:
      通用 HTTP 身份驗證框架有多個驗證方案使用。不一樣的驗證方案會在安全強度上有所不一樣。HTTP Auth Authentication 是最經常使用的 HTTP認證方案,爲了減小泄露風險通常要求 HTTPS 協議。
    • 適用場景:
      通常多被用在內部安全性要求不高的的系統上,如路由器網頁管理接口
    • 問題:

      1. 請求上攜帶驗證信息,容易被嗅探到
      2. 沒法註銷
  • Cookie + Session:

    • 梳理總結:

      • 服務端存儲 session ,客戶端存儲 cookie,其中 cookie 保存的爲 sessionID
      • 能夠靈活 revoke 權限,更新信息後能夠方便的同步 session 中相應內容
      • 分佈式 session 通常使用 redis(或其餘KV) 存儲
    • 使用場景:
      適合傳統系統獨立鑑權
  • JWT:

    • 梳理總結:

      • 服務器再也不須要存儲 session,服務器認證鑑權業務能夠方便擴展
      • JWT 並不依賴 cookie,也可使用 header 傳遞
      • 爲減小盜用,要使用 HTTPS 協議傳輸
    • 適用場景:

      • 適合作簡單的 RESTful API 認證
      • 適合一次性驗證,例如註冊激活連接
    • 問題:

      1. 使用過程當中沒法廢棄某個 token,有效期內 token 一直有效
      2. payload 信息更新時,已下發的 token 沒法同步
  • OAuth:

    • 梳理總結:

      • OAuth是一個開放標準,容許用戶受權第三方應用訪問他們存儲在另外的服務提供者上的信息,而不須要將用戶名和密碼提供給第三方移動應用或分享他們數據的全部內容。
      • GitHub OAuth 文檔 Identifying and authorizing users for GitHub Apps
    • 適用場景:
      OAuth 分爲下面四種模式

      1. 簡化模式,不安全,適用於純靜態頁面應用
      2. 受權碼模式,功能最完整、流程最嚴密的受權模式,一般使用在公網的開放平臺中
      3. 密碼模式,通常在內部系統中使用,調用者是以用戶爲單位。
      4. 客戶端模式,通常在內部系統之間的 API 調用。兩個平臺之間調用,以平臺爲單位。
相關文章
相關標籤/搜索