在一頁式網頁架設登入系統通常是一件非常麻煩棘手的事情,

在一開始要思考的是該挑選哪個主流框架 Angular、React或Vue…

然後開始建立一個前後端分離的架構,只透過RESTful API來進行溝通,

在這樣的架構下,搭建CMS相當容易,前端通常只需要取得資料後,進行render出來即可,

##SESSION BASE 無用武之地 如果要建設會員或管理者權限功能,傳統 session-based 的權限登入方式相當簡單,

但是在透過 RESTful API 應用的框架中,session-based的方式則行不通,

此外,單純使用SESSION的情況,也必須解決資料跨 Server 的問題

Token

Token是一串加密字串,並儲存在前端, 當使用者再次操作時,就能在後端從資料庫中比對token, 檢查是否為有效的使用者, 但是這樣的查詢也會產生伺服器的負擔

JSON Web Tokens

JSON Web Tokens (JWT)

這裡要介紹的 JSON Web Tokens 簡稱 JWT,由Auth0所開發,

JWT是一個開源標準規範(RFC7519),就是用處理一頁式網站的權限驗證以及訊息交流等用途

他擁有 Json 的簡潔特性,又能像 Security Assertion Markup Language Tokens (SAML) 一樣可以夾帶多元訊息

相對於一般 Simple Web Tokens (SWT)僅能使用一般的token方式加密

JWT有著像SAML一樣的 公/私鑰的 (X.509認證) 加密方式,更加具有彈性

這裡,可以先透過官方的JSON Web Token (JWT) 結構圖,來解它的基本運作原理

從圖示範例提到,當我們傳送帳號密碼給後端,

後端就會產生 JWT Base64Url encoded 結構字串,這個JWT結構包含三部分: - 標頭 Header - 內容 Payload - 簽屬加密 Signature

程式格式如下所示:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

最後會編譯成這樣的格式: xxxxx.yyyyy.zzzzz

這裡我們先分別說明這三部分所包含的意思:

第一部分 標頭 Header

Header 是 JWT 第一部分的 Base64Url encoded字串 Header 包含兩個部分 alg 是hashing 演算法,例如 HMAC SHA256 (HS256) or RSA (RS256)

{
  "alg": "HS256",//加密類型
  "typ": "JWT"//定義類型
}

再將內容進行 base64 處理

第二部分 內容 Payload

Playload 是 JWT 第二部分的 Base64Url encoded字串 Playload 包含請求聲明(claims)的內容,內容包含三種形式

  • 預設聲明字串(Reserved claims) 每次無論請求甚麼內容,都會返回的固定格式, 非強制但建議要使用預設字串,例如: token有效時間(exp)、發行者(iss)、主體ID(sub)、對話者ID(aud)
  • 公開聲明字串(Public claims) 用於聲明領域, 使用namespace來避免api重複或碰撞導致無法預期的結果
  • 私密聲明字串(Private claims) 透過自定義字串,客製出溝通雙方才知道的字串

所以在Payload可以放的是能夠公開的資訊 (勿存放密碼、信用卡資料等) 例如:

{
  "token":xxxxxx,
  "iss":"0000000",
  "aud":123,
  ...
    "title":"Why sky is blue",
    "author":"John",
    "admin":true
}

再將內容進行 base64 處理

第三部分 簽屬加密 Signature

透過最後一部,開始進行 Signature 演算法編譯 編譯的方式會直接參考 Header 的設定值(HMAC SHA256 (HS256) or RSA (RS256))來進行加密演算 除了會包含Header與Payload,會再夾帶一個 secret密碼 (只有你知道,並且儲存在後端伺服器) 可以避免前端 token 遭到串改

Secret : 可以隨機產生固定的長字串, 也就是前面提到的格式,以這樣的方式進行組成JWT 這裡看一下,使用sha256(base64(標頭)+base64(內容字串)+加密字串) 的方式建構, 其中的 secret 就是只有我們知道的字串

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

最後再將 Signature 字串進行 base64處理

PHP OAuth2

http://oauth2.thephpleague.com/

參考 easyangularjs authentication with auth0