寫在前面
頭髮掉得多了,總有機會接觸/調到各種各樣的介面,各種面向Api程式設計實際上已經嵌入到我們的習慣中,沒辦法現在服務端通訊還得是http(s),其他協議還未能成為通用的。
大廠的開發平臺api我先不敢說,各種小公司、或者不少大公司內部之間,各種各樣的的介面簽名/授權方式可以說是盡顯勞動人民智慧、八仙過海,各顯神通。當然,我也曾是八仙中一員大將;
然而,不能總當神仙,偶爾也要做下凡人。下面我們聊聊常見的服務授權方式;
Basic Auth
Basic Auth使用base64編碼把 username
:password
(注意中間有個半形冒號)加密後放入請求頭:
比如賬號密碼 hei:123 , base64後在request--header這樣:
Authorization: Basic aGVpOjEyMw==
Postman支援
總結:
優點:簡單明瞭,特別容易理解;
缺點:因為簡單,且幾乎是明文的形式傳遞,總得來說不夠安全;且要配合許可權啊、授權策略啊要花挺多成本;
看場景使用;
Key Auth
這個別看名字起得高大上,其實也就是你先定義一個 KeyName,KeyValue,呼叫方和介面定義方約定這個Key放在--header或者Query Params裡,到時按約定好的取出就好;
比如我定義了的
KeyName: apikey
KeyValue: hei.key.7LimLB5qXHtuBsI7HpxM9mj447ME3GlNoe7WxKL5
約定好放到Header裡。
Postman支援
總結: 跟basic auth 一樣,還是不夠安全,雖然可以通過新增超複雜的keyValue提高安全性。但記住,只要是固定的key,永遠都是不安全的。看場景使用。
Jwt Auth
這個知識點可是可是部落格園的常客了,三天兩頭都有相關博文;但畢竟本片不是jwt專題,我就不長篇闊論了簡單聊聊;
首先jwt是啥
Json web token (JWT), 是為了在網路應用環境間傳遞宣告而執行的一種基於JSON的開放標準((RFC 7519),
傳遞資訊的標準的說白了就是一種資料格式,它分成三個部分組成,中間用.
隔開:
(圖來自龍哥的部落格)
//上圖三部分一般這樣組成,所以整個jwt都是base64的(除了那兩個分割的'.')
base64Url(Header)+"."+base64Url(Payload)+"."+base64Url(Signature)
具體的一個jwt
eyJhbGciOiJSUzI1NiIsImtpZCI6IjY1OTMxODE4QjYxQkIzQTVEMUIxN0Y0MEVCRTlEQkY2IiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE1OTcxNDIxNzgsImV4cCI6MTU5NzE0OTM3OCwiaXNzIjoiaHR0cDovLzE3Mi4xNi4zLjExNzo1MTAwIiwiYXVkIjpbIm9jZWxvdCIsImh0dHA6Ly8xNzIuMTYuMy4xMTc6NTEwMC9yZXNvdXJjZXMiXSwiY2xpZW50X2lkIjoib2NlbG90LmNsaWVudCIsImp0aSI6IkQxRkExNkE3MkM1RDY4RDEyMTMzM0RGRjRDRDBCM0Q4IiwiaWF0IjoxNTk3MTQyMTc4LCJzY29wZSI6WyJvY2Vsb3QuYWRtaW4iXX0.PCN_Q77r0IyaesLy-Q0lTV12EYD9GkywrDMfxrCBj3ac9YltW8RzczAqdn2f92iysf_5Iu6hvTm16z9MJay6-eGWBiuIgJRXaCDlTqWWKcI8rWmW17ncyJT5oIgwip54Tfder9AfJOUJ-K0U2zT0fsrnBf7CZDLmkAAFHoxky1dzmPnh7JM4EkjtC-ybLOu_Aav7GgIOyYfodovxNgMvGHdhmheJLjxpjGblfI6o3rH8fRedwoV8zCY8MxJRGVcqg8slo0E9wfsebNx8hCV1mLHJbuDbJ1DCnDQ_1I1pFEFZCVNE2g0R-LRMC7opfFcveorNvZcJ8zEPWcACqoGXZg
我們 複製到https://jwt.io/ 解析看看:
可以很清楚的看到, header部分是說明Token的型別和所使用的演算法,payload部分就是授權資訊,比如使用者名稱啊、哪個伺服器,什麼時候發的、什麼時候失效等等。signature部分是簽名資訊,防止篡改。
一般是怎麼用jwt的
我借龍哥個圖來說明下
- 一般我們先定義一個頒發token服務(Auth Service --Api),服務呼叫方攜帶授權資訊申請token;
- Auth Service驗證授權資訊後返回jwt;
- 服務呼叫方攜帶jwt請求受保護介面;
- 受保護介面驗證jwt 的有效性,驗證有沒有許可權、是否在有效期、有沒有被篡改等(這裡不用到Auth Service驗,也就是去中心化的方式,這是jwt的一大有點)。這裡寫著是閘道器,其實也可以寫在介面的過濾器那裡,不過這樣每個專案都要實現一遍驗證邏輯了。
- 這裡已經解析完jwt,打擾可以攜帶jwt的資訊去呼叫介面啦;
- 響應,流程完;
其實大家都差不多這麼用的,不管是自定義實現還是用第三方的中介軟體形式,具體看需求;
Postman支援
總結:
優點
-
因為json的通用性,所以JWT是可以進行跨語言支援;
-
因為有了payload部分,所以JWT可以在自身儲存一些其他業務邏輯所必要的非敏感資訊。
-
便於傳輸,jwt的構成非常簡單,傳輸位元組不大,高效能。
-
去中心化,高效能;
缺點
- 安全性:如果是完全去中心化的方式,如果jwt給黑客擷取了,是沒有辦法吊銷的,開發的時候可以考慮下如何解決這個問題;
- 攜帶的資訊是完全開放的,不能攜帶安全性高的加密資訊,只能說有限安全性,依然看場景使用,不過我的經驗,日常開發絕大部分時候夠用了。
Oauth2--client_credentials(客戶端憑證)模式
Oauth2.0 有多種模式,比如Authorization Code、Implicit Flow、Password Grant等、我們今天只來看client_credentials--客戶端配置模式吧。
我們先看官方的流程圖:
+---------+ +---------------+
| | | |
| |>--(A)- Client Authentication --->| Authorization |
| Client | | Server |
| |<--(B)---- Access Token ---------<| |
| | | |
+---------+ +---------------+
可以看到非常簡單,他其實只要:
A、Client攜帶授權資訊(client_id,client_scret,scopes,grant_type等)去Authorization Server 申領AccessToken;
B、Authorization Server 頒發AccessToken;
然後你就可以用這個AccessToken 呼叫 受保護的介面了;
我們來看看例項:
1、先請求AccessToken
2、攜帶AccessToken 呼叫受保護介面
Postman支援
其實這裡的header是這樣的:
Authorization: Bearer ZJg0rak2ZYKyZeBTH7zJzDl94AjkfwiE
那可以看到我們的AccessToken ,很明顯很簡短,看情況是不攜帶任何資訊的。那意味著它每次呼叫都需要去Authorization Server驗證AccessToken 才行,這樣介面呼叫量瞬間翻倍了,效能肯定受影響。我們能不能像上面提到的jwt一樣,用jwt 做token,去中心化呢?
答案是可以的,Oauth2.0-client_credentials模式本身是對流程的標準化,並沒有限制token型別,所以我們是可以用jwt做token,但是又涉及到一個問題授權是OAth2.0的活,如果你加入jwt做身份區分那其實已經是OpenId Connect的活了,那又是另一個話題了。但那其實是一個非常好的設計,我們.net core裡面就用這麼個方案實現的框架IdentityServer4;
總結:identityserver4真香;
Hmac Auth
Hmac的全稱是Hash-based Message Authentication Code(基於雜湊的訊息認證碼), 看起來有點蒙,我們先來看個例子,比如我們有如下的介面地址:
http://api.hei.com?userid=23233&age=18&type=normal
我們經常會這樣給我們介面加簽名:
- 先把query引數全小寫後,按a-z排序為,用&隔開:age=18&type=normal&userid=23233
- 對引數32位小寫md5, md5_32(“age=18&type=normal&userid=23233”) 得到sign:a8b8a635cc34b95a8788abfa6f6b9ff2
- 把sign加在請求引數後面:http://api.hei.com?userid=23233&age=18&type=normal&sign=a8b8a635cc34b95a8788abfa6f6b9ff2
- 服務端按同樣的方法驗證引數;
如果我們把以上的 md5_32(“排序引數”)加“鹽”改為:md5_32(my_secret_key,“排序引數”) 這就是:
Hmac-Md5 演算法,同理,還有:
Hmac-SHA1
Hmac-SHA384
Hmac-SHA256
Hmac-SHA512
等等演算法,主要的區別在於雜湊演算法的不同。因為安全性有一定的報障,各種語言裡面都會有對應的語言無關的實現,比如.net core 裡面就有:HMACMD5、HMACSHA1、HMACSHA256、HMACSHA384、HMACSHA512 這五個內建類,都是呼叫裡面的ComputeHash()。
當然,生產中的例子可能不像上面的那麼簡單,比如介面呼叫方要求一定附加一個時間戳引數在請求裡,5分鐘內本請求有效,my_secret_key 非常複雜,動態 my_secret_key 等等方式。
這個Postman當然支援:
這是我用閘道器kong內建的Hmac Auth 外掛實現的。
總結:
大總結
我覺得介面認證授權這塊挺多東西,我現在用IdentityServer4+Hmac比較多,大家平時怎麼處理的,也可以聊一聊~
參考
https://www.cnblogs.com/edisonchou/p/talk_about_what_is_jwt.html