摘要:認證服務器,即服務提供商專門用來處理認證的服務器。它與認證服務器,可以是同一臺服務器,也可以是不同的服務器。客戶端使用上一步獲得的授權,向認證服務器申請令牌。認證服務器對客戶端進行認證以后,確認無誤,同意發放令牌。
幾種常用的認證機制 HTTP Basic Auth最近想做個小程序,需要用到授權認證流程。以前項目都是用的 OAuth2 認證,但是Sanic 使用OAuth2 不太方便,就想試一下 JWT 的認證方式。
這一篇主要內容是 JWT 的認證原理,以及python 使用 jwt 認識的實踐。
HTTP Basic Auth 在HTTP中,基本認證是一種用來允許Web瀏覽器或其他客戶端程序在請求時提供用戶名和口令形式的身份憑證的一種登錄驗證方式,通常用戶名和明碼會通過HTTP頭傳遞。
在發送之前是以用戶名追加一個冒號然后串接上口令,并將得出的結果字符串再用Base64算法編碼。例如,提供的用戶名是Aladdin、口令是open sesame,則拼接后的結果就是Aladdin:open sesame,然后再將其用Base64編碼,得到QWxhZGRpbjpvcGVuIHNlc2FtZQ==。最終將Base64編碼的字符串發送出去,由接收者解碼得到一個由冒號分隔的用戶名和口令的字符串。
優點
基本認證的一個優點是基本上所有流行的網頁瀏覽器都支持基本認證。
缺點
由于用戶名和密碼都是Base64編碼的,而Base64編碼是可逆的,所以用戶名和密碼可以認為是明文。所以只有在客戶端和服務器主機之間的連接是安全可信的前提下才可以使用。
接下來我們看一個更加安全也適用范圍更大的認證方式 OAuth。
OAuthOAuth 是一個關于授權(authorization)的開放網絡標準。允許用戶提供一個令牌,而不是用戶名和密碼來訪問他們存放在特定服務提供者的數據。現在的版本是2.0版。
嚴格來說,OAuth2不是一個標準協議,而是一個安全的授權框架。它詳細描述了系統中不同角色、用戶、服務前端應用(比如API),以及客戶端(比如網站或移動App)之間怎么實現相互認證。
名詞定義Third-party application: 第三方應用程序,又稱"客戶端"(client)
HTTP service:HTTP服務提供商
Resource Owner:資源所有者,通常稱"用戶"(user)。
User Agent:用戶代理,比如瀏覽器。
Authorization server:認證服務器,即服務提供商專門用來處理認證的服務器。
Resource server:資源服務器,即服務提供商存放用戶生成的資源的服務器。它與認證服務器,可以是同一臺服務器,也可以是不同的服務器。
OAuth 2.0 運行流程如圖:
(A)用戶打開客戶端以后,客戶端要求用戶給予授權。
(B)用戶同意給予客戶端授權。
(C)客戶端使用上一步獲得的授權,向認證服務器申請令牌。
(D)認證服務器對客戶端進行認證以后,確認無誤,同意發放令牌。
(E)客戶端使用令牌,向資源服務器申請獲取資源。
(F)資源服務器確認令牌無誤,同意向客戶端開放資源。
優點
快速開發
實施代碼量小
維護工作減少
如果設計的API要被不同的App使用,并且每個App使用的方式也不一樣,使用OAuth2是個不錯的選擇。
缺點:
OAuth2是一個安全框架,描述了在各種不同場景下,多個應用之間的授權問題。有海量的資料需要學習,要完全理解需要花費大量時間。
OAuth2不是一個嚴格的標準協議,因此在實施過程中更容易出錯。
了解了以上兩種方式后,現在終于到了本篇的重點,JWT 認證。
JWT 認證JWT 特點Json web token (JWT), 根據官網的定義,是為了在網絡應用環境間傳遞聲明而執行的一種基于JSON的開放標準((RFC 7519).該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。
體積小,因而傳輸速度快
傳輸方式多樣,可以通過URL/POST參數/HTTP頭部等方式傳輸
嚴格的結構化。它自身(在 payload 中)就包含了所有與用戶相關的驗證消息,如用戶可訪問路由、訪問有效期等信息,服務器無需再去連接數據庫驗證信息的有效性,并且 payload 支持為你的應用而定制化。
支持跨域驗證,可以應用于單點登錄。
JWT原理JWT是Auth0提出的通過對JSON進行加密簽名來實現授權驗證的方案,編碼之后的JWT看起來是這樣的一串字符:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
由 . 分為三段,通過解碼可以得到:
1. 頭部(Header)// 包括類別(typ)、加密算法(alg); { "alg": "HS256", "typ": "JWT" }
jwt的頭部包含兩部分信息:
聲明類型,這里是jwt
聲明加密的算法 通常直接使用 HMAC SHA256
然后將頭部進行base64加密(該加密是可以對稱解密的),構成了第一部分。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ92. 載荷(payload)
載荷就是存放有效信息的地方。這些有效信息包含三個部分:
標準中注冊聲明
公共的聲名
私有的聲明
公共的聲明 :
公共的聲明可以添加任何的信息,一般添加用戶的相關信息或其他業務需要的必要信息.但不建議添加敏感信息,因為該部分在客戶端可解密。
私有的聲明 :
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為base64是對稱解密的,意味著該部分信息可以歸類為明文信息。
下面是一個例子:
// 包括需要傳遞的用戶信息; { "iss": "Online JWT Builder", "iat": 1416797419, "exp": 1448333419, "aud": "www.gusibi.com", "sub": "uid", "nickname": "goodspeed", "username": "goodspeed", "scopes": [ "admin", "user" ] }
iss: 該JWT的簽發者,是否使用是可選的;
sub: 該JWT所面向的用戶,是否使用是可選的;
aud: 接收該JWT的一方,是否使用是可選的;
exp(expires): 什么時候過期,這里是一個Unix時間戳,是否使用是可選的;
iat(issued at): 在什么時候簽發的(UNIX時間),是否使用是可選的;
其他還有:
nbf (Not Before):如果當前時間在nbf里的時間之前,則Token不被接受;一般都會留一些余地,比如幾分鐘;,是否使用是可選的;
jti: jwt的唯一身份標識,主要用來作為一次性token,從而回避重放攻擊。
將上面的JSON對象進行base64編碼可以得到下面的字符串。這個字符串我們將它稱作JWT的Payload(載荷)。
eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0
3. 簽名(signature)信息會暴露:由于這里用的是可逆的base64 編碼,所以第二部分的數據實際上是明文的。我們應該避免在這里存放不能公開的隱私信息。
// 根據alg算法與私有秘鑰進行加密得到的簽名字串; // 這一段是最重要的敏感信息,只能在服務端解密; HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), SECREATE_KEY )
jwt的第三部分是一個簽證信息,這個簽證信息由三部分組成:
header (base64后的)
payload (base64后的)
secret
將上面的兩個編碼后的字符串都用句號.連接在一起(頭部在前),就形成了:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9
最后,我們將上面拼接完的字符串用HS256算法進行加密。在加密的時候,我們還需要提供一個密鑰(secret)。如果我們用 secret 作為密鑰的話,那么就可以得到我們加密后的內容:
pq5IDv-yaktw6XEa5GEv07SzS9ehe6AcVSdTj0Ini4o
將這三部分用.連接成一個完整的字符串,構成了最終的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0MTY3OTc0MTksImV4cCI6MTQ0ODMzMzQxOSwiYXVkIjoid3d3Lmd1c2liaS5jb20iLCJzdWIiOiIwMTIzNDU2Nzg5Iiwibmlja25hbWUiOiJnb29kc3BlZWQiLCJ1c2VybmFtZSI6Imdvb2RzcGVlZCIsInNjb3BlcyI6WyJhZG1pbiIsInVzZXIiXX0.pq5IDv-yaktw6XEa5GEv07SzS9ehe6AcVSdTj0Ini4o
簽名的目的:簽名實際上是對頭部以及載荷內容進行簽名。所以,如果有人對頭部以及載荷的內容解碼之后進行修改,再進行編碼的話,那么新的頭部和載荷的簽名和之前的簽名就將是不一樣的。而且,如果不知道服務器加密的時候用的密鑰的話,得出來的簽名也一定會是不一樣的。
這樣就能保證token不會被篡改。
token 生成好之后,接下來就可以用token來和服務器進行通訊了。
下圖是client 使用 JWT 與server 交互過程:
這里在第三步我們得到 JWT 之后,需要將JWT存放在 client,之后的每次需要認證的請求都要把JWT發送過來。(請求時可以放到 header 的 Authorization )
JWT 使用場景JWT的主要優勢在于使用無狀態、可擴展的方式處理應用中的用戶會話。服務端可以通過內嵌的聲明信息,很容易地獲取用戶的會話信息,而不需要去訪問用戶或會話的數據庫。在一個分布式的面向服務的框架中,這一點非常有用。
但是,如果系統中需要使用黑名單實現長期有效的token刷新機制,這種無狀態的優勢就不明顯了。
優點
快速開發
不需要cookie
JSON在移動端的廣泛應用
不依賴于社交登錄
相對簡單的概念理解
缺點
Token有長度限制
Token不能撤銷
需要token有失效時間限制(exp)
我基本是使用 python 作為服務端語言,我們可以使用 pyjwt:https://github.com/jpadilla/pyjwt/
使用比較方便,下邊是我在應用中使用的例子:
import jwt import time # 使用 sanic 作為restful api 框架 def create_token(request): grant_type = request.json.get("grant_type") username = request.json["username"] password = request.json["password"] if grant_type == "password": account = verify_password(username, password) elif grant_type == "wxapp": account = verify_wxapp(username, password) if not account: return {} payload = { "iss": "gusibi.com", "iat": int(time.time()), "exp": int(time.time()) + 86400 * 7, "aud": "www.gusibi.com", "sub": account["_id"], "username": account["username"], "scopes": ["open"] } token = jwt.encode(payload, "secret", algorithm="HS256") return True, {"access_token": token, "account_id": account["_id"]} def verify_bearer_token(token): # 如果在生成token的時候使用了aud參數,那么校驗的時候也需要添加此參數 payload = jwt.decode(token, "secret", audience="www.gusibi.com", algorithms=["HS256"]) if payload: return True, token return False, token
這里,我們可以使用 jwt 直接生成 token,不用手動base64加密和拼接。
詳細代碼可以參考 gusibi/Metis: 一個測試類小程序(包含前后端代碼)。
這個項目中,api 使用 python sanic,文檔使用 swagger-py-codegen 生成,提供 swagger ui。
現在可以使用 swagger ui 來測試jwt。
總結這一篇主要介紹了 jwt 的原理、驗證步驟,最后是使用 pyjwt 包演示 生成token以及校驗token的方法。
預告,下一篇是介紹小程序中使用 JWT 的認證流程及實現。 參考鏈接以上提到的包可以在公號回復關鍵字獲取地址
HTTP基本認證
訪問需要HTTP Basic Authentication認證的資源的各種語言的實現
理解OAuth 2.0
OAuth 2和JWT - 如何設計安全的API?
Securing RESTful Web Services with OAuth2
Server 端的認證——擁抱
JSON Web Token - 在Web應用間安全地傳遞信息
八幅漫畫理解使用JSON Web
基于Token的WEB后臺認證機制
什么是 JWT -- JSON WEB TOKEN
最后,感謝女朋友支持。
歡迎關注(April_Louisa) | 請我喝芬達 |
---|---|
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/40655.html
摘要:詳細介紹可以查看這篇文章理解認證及實踐特點優點體積小,因而傳輸速度快傳輸方式多樣,可以通過參數頭部等方式傳輸嚴格的結構化。 Json web token (JWT), 根據官網的定義,是為了在網絡應用環境間傳遞聲明而執行的一種基于JSON的開放標準((RFC 7519).該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和...
摘要:參考鏈接微信小程序七日談第五天你可能要在登錄功能上花費大力氣理解認證及實踐網站微信登錄實現最后,感謝女朋友支持。 開發微信小程序時,接入小程序的授權登錄可以快速實現用戶注冊登錄的步驟,是快速建立用戶體系的重要一步。這篇文章將介紹 python + sanic + 微信小程序實現用戶快速注冊登錄全棧方案。 微信小程序登錄時序圖如下: showImg(https://segmentfaul...
摘要:參考鏈接微信小程序七日談第五天你可能要在登錄功能上花費大力氣理解認證及實踐網站微信登錄實現最后,感謝女朋友支持。 開發微信小程序時,接入小程序的授權登錄可以快速實現用戶注冊登錄的步驟,是快速建立用戶體系的重要一步。這篇文章將介紹 python + sanic + 微信小程序實現用戶快速注冊登錄全棧方案。 微信小程序登錄時序圖如下: showImg(https://segmentfaul...
摘要:要對進行黑盒測試測試的最好辦法是對他們進行黑盒測試,黑盒測試是一種不關心應用內部結構和工作原理的測試方法,測試時系統任何部分都不應該被。此外,有了黑盒測試并不意味著不需要單元測試,針對的單元測試還是需要編寫的。 本文首發于之乎專欄前端周刊,全文共 6953 字,讀完需 8 分鐘,速度需 2 分鐘。翻譯自:RingStack 的文章 https://blog.risingstack.co...
摘要:自己在前后端分離上的實踐要想實現完整的前后端分離,安全這塊是繞不開的,這個系統主要功能就是動態管理,這次實踐包含兩個模塊基于搭建的權限管理系統后臺編寫的前端管理。 自己在前后端分離上的實踐 要想實現完整的前后端分離,安全這塊是繞不開的,這個系統主要功能就是動態restful api管理,這次實踐包含兩個模塊,基于springBoot + shiro搭建的權限管理系統后臺bootshir...
閱讀 1165·2021-11-24 09:39
閱讀 3632·2021-09-02 15:21
閱讀 2174·2021-08-24 10:01
閱讀 735·2021-08-19 10:55
閱讀 2459·2019-08-30 15:55
閱讀 1221·2019-08-30 14:16
閱讀 3005·2019-08-29 15:17
閱讀 3245·2019-08-29 13:53