溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何用Golang實(shí)現(xiàn)一套靈活的JWT庫

發(fā)布時(shí)間:2021-11-24 14:14:41 來源:億速云 閱讀:217 作者:柒染 欄目:編程語言

如何用Golang實(shí)現(xiàn)一套靈活的JWT庫,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

JWT 全 chen JSON Web Tokens 現(xiàn)在被廣泛的應(yīng)用于各種前后端分離的場(chǎng)景,他比傳統(tǒng)的 Token Session  方式,更具靈活性。

當(dāng)然網(wǎng)上也有很多開源的 JWT 庫,非常之多,開源組織也提供了官方的庫。

我最近自己寫的一個(gè) JWT 庫,代碼已經(jīng)上傳到 github 上了,地址如下:

  • https://github.com/liu578101804/go-tool/tree/master/jwt

相比出名的 JWT 庫來說,我沒有任何優(yōu)勢(shì),只是作為學(xué)習(xí)使用,歡迎大家指正其中的不足。

下面就給大家說下我的實(shí)現(xiàn)思路吧。

JWT 的原理

我們要實(shí)現(xiàn) JWT 算法就得先了解他的原理,我盡量用剪短的話去解釋:

JWT 算法輸出的數(shù)據(jù)是一串包含 header(頭信息).payload(內(nèi)容).signature(簽名) 的一段字符串。

來一段真實(shí)的 JWT 生成的字符串:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

是不是豁然開朗了,這串字符串又叫 token ,因?yàn)檫@串 token 里面包含了驗(yàn)證需要的信息,相比傳統(tǒng)的 session  需要到服務(wù)器里面去取驗(yàn)證的信息,更加的靈活獨(dú)立。

因?yàn)樗灰蕾?session 這種傳統(tǒng)的存儲(chǔ),別用在分布式服務(wù)器里面有著很大的優(yōu)勢(shì)。

當(dāng)然他也有缺點(diǎn),最頭痛就這 2 點(diǎn):

  • 不可控。一旦簽發(fā)出去的 token 將無法提前讓他銷毀,不像傳統(tǒng)的,我可以把我 session 里面的 token 刪了下次過來,token  就失效了。當(dāng)然這也不是沒辦法解決,在整個(gè)體系里面加入黑名單機(jī)制就行,只是稍微麻煩了點(diǎn)。

  • 信息相對(duì)傳統(tǒng)的 session 數(shù)據(jù)量和隱私性沒那么好。因?yàn)?token 一般都不建議特別長(zhǎng),所以 payload 承載的數(shù)據(jù)量是有限的。同時(shí)字符串里面的  payload 是可以被解密的,所以存在一定性的被破譯風(fēng)險(xiǎn)(當(dāng)然你可以使用比較難破譯的算法去降低這個(gè)風(fēng)險(xiǎn))。

算法組成

JWT 的算法組成很簡(jiǎn)單,只需要 一個(gè)可逆的加密算法去加密  header(頭信息).payload(內(nèi)容),一個(gè)不可逆的算法去對(duì)前面這部分內(nèi)容進(jìn)行加密簽名生成 signature(簽名) 就行。

如果我們用不同的加密算法組合便形成了不同的 JWT 加密算法。比如:

  • HS256 (HMAC + SHA-256)

  • RS256 (RSA + SHA-256)

當(dāng)然還有很多,你可以自己去組合,我們將寫的這個(gè)庫支持你自定義。

具體實(shí)現(xiàn)

下面就開始進(jìn)入代碼實(shí)現(xiàn)階段了:

說下我的設(shè)計(jì)思路,Golang  他有一個(gè)天然的優(yōu)勢(shì)就是支持把函數(shù)作為變量傳入,我們便可以根據(jù)這一特性把加密部分讓調(diào)用者去實(shí)現(xiàn),我們把實(shí)現(xiàn)主體就行,這樣便我們的 JWT 便非常靈活了。

我們要寫的主體代碼去掉注釋空行不到 100 行。

jwt.go

package jwt  import (     "encoding/json"     "strings"     "fmt" )  //聲明一個(gè)標(biāo)準(zhǔn)的JWT接口 type IJwt interface {     //設(shè)置頭部     SetHeader(string)     //設(shè)置簽名算法     SetSignFunc(SignFunc)     //設(shè)置編碼算法     SetEncodeFunc(EncodeFunc)      //寫入body     WriteBody(map[string]interface{})      //生成jwt     CreateJwtString() (string,error)     //驗(yàn)證jwt     CheckJwtString(string) bool }  //規(guī)范header的格式 type Header struct {     Type    string  `json:"type"`     Alg     string  `json:"alg"` }  //簽名算法 type SignFunc func([]byte) string //編碼算法 type EncodeFunc func([]byte) string   //聲明一個(gè)結(jié)構(gòu)圖 去實(shí)現(xiàn) 標(biāo)準(zhǔn)的JWT接口 type Jwt struct {     Header      Header     Body        map[string]interface{}      signFun     SignFunc     encodeFun   EncodeFunc }  //設(shè)置頭部信息,說明你使用的簽名算法 func (j *Jwt) SetHeader(headerType string){     j.Header =  Header{         Type: "JWT",         Alg: headerType,     } }  //設(shè)置簽名算法 func (j *Jwt) SetSignFunc(signFunc SignFunc) {     j.signFun = signFunc }  //設(shè)置對(duì) header 和 body 的加密算法 func (j *Jwt) SetEncodeFunc(encodeFunc EncodeFunc) {     j.encodeFun = encodeFunc }  //寫入要加密的內(nèi)容 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 }  //驗(yàn)證 token 是否合規(guī) 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 }

這個(gè)文件就已經(jīng)把 JWT 的核心給寫好了,現(xiàn)在只需要根據(jù)你想要的加密算法進(jìn)行填充就好了。

下面我們就去實(shí)現(xiàn)一個(gè)最簡(jiǎn)單的 RS256 算法,新建一個(gè) bs.go 文件,內(nèi)容如下:

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 當(dāng)然這種算法生成的 JWT  很容易被人串改模仿,不能用于生產(chǎn)的。

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI