您好,登錄后才能下訂單哦!
如何用Golang實現一套靈活的JWT庫,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
JWT 全 chen JSON Web Tokens 現在被廣泛的應用于各種前后端分離的場景,他比傳統的 Token Session 方式,更具靈活性。
當然網上也有很多開源的 JWT 庫,非常之多,開源組織也提供了官方的庫。
我最近自己寫的一個 JWT 庫,代碼已經上傳到 github 上了,地址如下:
https://github.com/liu578101804/go-tool/tree/master/jwt
相比出名的 JWT 庫來說,我沒有任何優勢,只是作為學習使用,歡迎大家指正其中的不足。
下面就給大家說下我的實現思路吧。
JWT 的原理
我們要實現 JWT 算法就得先了解他的原理,我盡量用剪短的話去解釋:
JWT 算法輸出的數據是一串包含 header(頭信息).payload(內容).signature(簽名) 的一段字符串。
來一段真實的 JWT 生成的字符串:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
是不是豁然開朗了,這串字符串又叫 token ,因為這串 token 里面包含了驗證需要的信息,相比傳統的 session 需要到服務器里面去取驗證的信息,更加的靈活獨立。
因為他不依賴 session 這種傳統的存儲,別用在分布式服務器里面有著很大的優勢。
當然他也有缺點,最頭痛就這 2 點:
不可控。一旦簽發出去的 token 將無法提前讓他銷毀,不像傳統的,我可以把我 session 里面的 token 刪了下次過來,token 就失效了。當然這也不是沒辦法解決,在整個體系里面加入黑名單機制就行,只是稍微麻煩了點。
信息相對傳統的 session 數據量和隱私性沒那么好。因為 token 一般都不建議特別長,所以 payload 承載的數據量是有限的。同時字符串里面的 payload 是可以被解密的,所以存在一定性的被破譯風險(當然你可以使用比較難破譯的算法去降低這個風險)。
算法組成
JWT 的算法組成很簡單,只需要 一個可逆的加密算法去加密 header(頭信息).payload(內容),一個不可逆的算法去對前面這部分內容進行加密簽名生成 signature(簽名) 就行。
如果我們用不同的加密算法組合便形成了不同的 JWT 加密算法。比如:
HS256 (HMAC + SHA-256)
RS256 (RSA + SHA-256)
當然還有很多,你可以自己去組合,我們將寫的這個庫支持你自定義。
具體實現
下面就開始進入代碼實現階段了:
說下我的設計思路,Golang 他有一個天然的優勢就是支持把函數作為變量傳入,我們便可以根據這一特性把加密部分讓調用者去實現,我們把實現主體就行,這樣便我們的 JWT 便非常靈活了。
我們要寫的主體代碼去掉注釋空行不到 100 行。
jwt.go
package jwt import ( "encoding/json" "strings" "fmt" ) //聲明一個標準的JWT接口 type IJwt interface { //設置頭部 SetHeader(string) //設置簽名算法 SetSignFunc(SignFunc) //設置編碼算法 SetEncodeFunc(EncodeFunc) //寫入body WriteBody(map[string]interface{}) //生成jwt CreateJwtString() (string,error) //驗證jwt CheckJwtString(string) bool } //規范header的格式 type Header struct { Type string `json:"type"` Alg string `json:"alg"` } //簽名算法 type SignFunc func([]byte) string //編碼算法 type EncodeFunc func([]byte) string //聲明一個結構圖 去實現 標準的JWT接口 type Jwt struct { Header Header Body map[string]interface{} signFun SignFunc encodeFun EncodeFunc } //設置頭部信息,說明你使用的簽名算法 func (j *Jwt) SetHeader(headerType string){ j.Header = Header{ Type: "JWT", Alg: headerType, } } //設置簽名算法 func (j *Jwt) SetSignFunc(signFunc SignFunc) { j.signFun = signFunc } //設置對 header 和 body 的加密算法 func (j *Jwt) SetEncodeFunc(encodeFunc EncodeFunc) { j.encodeFun = encodeFunc } //寫入要加密的內容 func (j *Jwt) WriteBody(body map[string]interface{}) { j.Body = body } //生成token func (j *Jwt) CreateJwtString() (string,error) { //編碼header headerByte,err := json.Marshal(j.Header) if err != nil { return "",err } headerStr := j.encodeFun(headerByte) //編碼body bodyByte,err := json.Marshal(j.Body) if err != nil { return "",err } bodyStr := j.encodeFun(bodyByte) //簽名 signByte := j.signFun([]byte(string(headerStr)+"."+string(bodyStr))) return fmt.Sprintf("%s.%s.%s",headerStr,bodyStr,signByte),nil } //驗證 token 是否合規 func (j *Jwt) CheckJwtString(input string) bool { arr := strings.Split(input,".") //格式是否正確 if len(arr) != 3 { return false } //簽名 signByte := j.signFun([]byte(string(arr[0])+"."+string(arr[1]))) if string(signByte) != arr[2] { return false } return true }
這個文件就已經把 JWT 的核心給寫好了,現在只需要根據你想要的加密算法進行填充就好了。
下面我們就去實現一個最簡單的 RS256 算法,新建一個 bs.go 文件,內容如下:
package jwt import ( "crypto/sha256" "encoding/base64" "fmt" ) func NewRS256() IJwt { jwtM := Jwt{} //Sha256 jwtM.SetSignFunc(func(bytes []byte) string { h := sha256.New() h.Write(bytes) return fmt.Sprintf("%x",h.Sum(nil)) }) //base64 jwtM.SetEncodeFunc(func(bytes []byte) string { return base64.URLEncoding.EncodeToString(bytes) }) return &jwtM }
我這里 header 和 payload 采用 base64 去加密,簽名采用 sha256 當然這種算法生成的 JWT 很容易被人串改模仿,不能用于生產的。
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。