open sesame(芝麻開門) - Ali Baba and the Forty Thieves
1. 需求場景
我們在開發(fā)api接口時嘁信,有時候需要對某些接口進行授權,允許有權限的用戶才能訪問屡律。對用戶進行權限管理通常可以通過cookie/session降淮,token等機制來實現超埋。這些方式比較適合相對復雜的業(yè)務權限處理,而http本身提供了一種相對簡單的授權方式佳鳖,就是http basic auth霍殴。上節(jié)中,我們提到的metrics相關的接口系吩,是需要進行授權后来庭,才能訪問,而監(jiān)控接口主要被內部的監(jiān)控系統(tǒng)所使用穿挨,本身和具體的業(yè)務無關月弛,使用http basic auth機制比較切合。
2. Basic Auth簡介
Basic Auth是http協(xié)議提供的一個簡單的認證機制絮蒿,當我們訪問某個受保護的資源(url)時尊搬,http服務器將告知客戶端該資源需要授權才能訪問,隨后客戶端提供相應的憑證(用戶名/密碼)土涝,服務端收到憑證進行校驗佛寿,確認無誤后,客戶端既可訪問受保護的資源,否則冀泻,將無權訪問常侣。
3. Basic Auth基本流程
3.1 瀏覽器交互流程
- 瀏覽器GET請求/actuator/metrics接口
- 服務器返回401響應,表示該資源需要授權訪問(basic auth)
- 瀏覽器彈出用戶名和密碼輸入框弹渔,讓用戶提供憑證胳施。用戶輸入信息后,將憑證信息進行相應的編碼后肢专,再次發(fā)送請求到服務器舞肆。
- 服務器收到用戶的請求,提取出用戶憑證博杖,校驗匹配后椿胯,返回包含該資源信息的200成功響應。
注意:
- 如用戶輸入的憑證信息不匹配剃根,將會再次執(zhí)行第二步操作哩盲,返回401響應(未授權)
- 不同的http客戶端,對basic auth的支持會有差異狈醉。典型的是通過瀏覽器訪問受保護的資源時廉油,會彈出用戶名和密碼輸入框,而非瀏覽器客戶端苗傅,比如在APP中抒线,通過http接口調用時,是不會彈出輸入框的渣慕。
3.2 http協(xié)議交互流程
下面我們具體的看一下http協(xié)議的交互流程十兢。
-
客戶端發(fā)起GET請求
GET /actuator/metrics HTTP/1.1 ...
-
服務器發(fā)現該資源需要授權訪問,而客戶端并未提供憑證信息摇庙,則向客戶端返回401響應(HTTP 401 Unauthorized),以及WWW-Authenticate頭部字段遥缕。
HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="Authorization Required" Date: Sun, 24 Mar 2019 01:09:45 GMT Content-Length: 0
WWW-Authenticate頭部字段:
WWW-Authenticate: Basic realm="Authorization Required"
其中卫袒,Basic表示使用basic認證算法,realm表示區(qū)域单匣,不同的區(qū)域可以使用不同的用戶名和密碼夕凝。
服務器也可以帶上編碼字段,表明服務器期望客戶端使用相應的編碼去encode用戶名和密碼户秤。
WWW-Authenticate: Basic realm="Authorization Required", charset="UTF-8"
-
客戶端獲取到用戶名和密碼后码秉,進行Base64編碼后,向服務器再次發(fā)起請求鸡号,請求中通常在header中通過Authorization字段帶上認證信息转砖。
GET /actuator/metrics HTTP/1.1 Host: localhost:9800 Authorization: Basic YWRtaW46cGFzcw== ...
Authorization字段信息包含兩部分,第一部分是Basic,后面帶上一個空格府蔗;第二部分是用戶憑證信息的編碼晋控。編碼過程如下:
- 將用戶名和密碼通過":"進行組合。這里要注意姓赤,用戶名中不能包含":"這個字符赡译。
- 將組合后的字符串默認使用US-ASCII編碼,當然服務器也可以要求使用UTF-8進行編碼不铆。
- 將組合后的字符串再通過Base64算法進行編碼蝌焚。
比如:用戶名為admin,密碼為pass誓斥,則編碼時先進行組裝得到字符串admin:pass只洒,然后對字符串使用ASCII編碼,進行Base64后得到字符串YWRtaW46cGFzcw==
-
服務器收到請求后岖食,提取出Authorization字段红碑,校驗匹配后,則返回200成功響應泡垃。
HTTP/1.1 200 OK Content-Type: application/json; charset=utf-8 Date: Sun, 24 Mar 2019 01:11:00 GMT Content-Length: 55 {"name":["all","mem.sys","mem.heap_objects","gc.last"]}
3.3 /health接口使用Basic Auth的特殊情況
/health接口在客戶端請求時析珊,如果沒有帶上basic auth信息,則返回簡單的服務健康信息蔑穴。
GET /actuator/health HTTP/1.1
...
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 30
...
{"status":"up","statusCode":1}
如果客戶端請求時忠寻,帶上了認證信息,則返回詳細的服務健康信息存和。
GET /actuator/health HTTP/1.1
Authorization: Basic YWRtaW46cGFzcw==
...
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Sun, 24 Mar 2019 02:37:13 GMT
Content-Length: 224
{"details":{"disk":{"status":"up","details":{"free":912524103680,"threshold":0,"total":1127625711616}},"mem":{"status":"up","details":{"free":10098888704,"total":1
7035321344,"used":6936432640}}},"status":"up","statusCode":1}
這里的實現和基本的basic auth流程將不一樣奕剃,它不會響應401。而是根據客戶端請求的情況進行處理捐腿。
func ActuatorGetHealthInfo(c *gin.Context) {
showDetail := false
// 判斷是否使用basic auth
authHead := c.GetHeader("Authorization")
if strings.HasPrefix(authHead, "Basic ") {
// 獲取token
token := authHead[6:]
// 驗證token
shouldToken := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", utils.GetAppConfig().Management.Security.Account, utils.GetAppConfig().Management.Security.Password)))
if token == shouldToken {
// 憑證信息一致纵朋,將顯示詳細信息
showDetail = true
}
}
// 調用業(yè)務邏輯
r, _ := healthService.HealthInfo(showDetail)
// 組裝返回數據
c.JSON(http.StatusOK, r)
}
4. Basic Auth優(yōu)缺點
4.1 Basic Auth優(yōu)點
- 簡單 - 認證信息使用標準的http頭部字段進行傳輸,不需要使用cookies/session等茄袖,也沒有復雜的客戶端和服務端協(xié)商過程操软。
4.2 Basic Auth缺點
- 安全 - 認證信息僅僅使用Base64進行編碼,并未使用加密算法宪祥,基本上等于明文傳輸聂薪,需要使用https進行加密傳輸。
5. Basic Auth應用場景
Basic Auth比較適合簡單的認證場景蝗羊,尤其是在內網中使用藏澳。通常我們會配合https進行信息加密,來提高安全性耀找。
6. 小結
本節(jié)通過實際的接口實例介紹了http basic auth的基本流程翔悠,優(yōu)缺點以及應用場景。下一節(jié),我們將介紹關于Restful接口的相關信息凉驻、如何設計Restful風格的接口及實際開發(fā)過程中比較好的工程實踐腻要。
本文為作者原創(chuàng)作品,屬于《重新學習web后端開發(fā)》專輯中的一篇涝登,轉載時請備注作者信息及來源雄家。本文原文地址:http://www.donnyzhang.com/2019/03/23/uranus-007/