golang原生實現(xiàn)JWT的示例代碼
JWT(JSON Web Token)是一種基于JSON的安全令牌,可以用于在不同系統(tǒng)之間傳輸認(rèn)證信息。在Go中實現(xiàn)JWT驗證,可以通過標(biāo)準(zhǔn)庫crypto/hmac
、crypto/sha256
和encoding/base64
來編寫自己的JWT。
獲取Token
我們在此封裝一個JWT的struct結(jié)構(gòu)體(由于除了Payload,其他很大可能不會在其他地方用到,所以不公開)
type JWT struct { header string Payload string signature string }
將base64的編碼封裝一下方便使用
func encodeBase64(data string) string { return base64.RawURLEncoding.EncodeToString([]byte(data)) }
我們封裝一個用來生成簽名的方法
func generateSignature(key []byte, data []byte) (string, error) { // 創(chuàng)建一個哈希對象 hash := hmac.New(sha256.New, key) // 將要簽名的信息寫入哈希對象中 hash.Write(data) _, err := hash.Write(data) if err != nil { return "", err } // hash.Sum()計算簽名,在這里會返回簽名內(nèi)容 // 將簽名經(jīng)過base64編碼生成字符串形式返回。 return encodeBase64(string(hash.Sum(nil))), nil }
我們封裝一個CreateToken用于生成Token(該方法的參數(shù)key為(生成簽名所使用的密鑰))
func CreateToken(key []byte, payloadData any) (string, error) { // 標(biāo)準(zhǔn)頭部 header := `{"alg":"HS256","typ":"JWT"}` // 將負(fù)載的數(shù)據(jù)轉(zhuǎn)換為json payload, jsonErr := json.Marshal(payloadData) if jsonErr != nil { return "", fmt.Errorf("負(fù)載json解析錯誤") } // 將頭部和負(fù)載通過base64編碼,并使用.作為分隔進(jìn)行連接 encodedHeader := encodeBase64(header) encodedPayload := encodeBase64(string(payload)) HeaderAndPayload := encodedHeader + "." + encodedPayload // 使用簽名使用的key將傳入的頭部和負(fù)載連接所得的數(shù)據(jù)進(jìn)行簽名 signature, err := generateSignature(key, []byte(HeaderAndPayload)) if err != nil { return "", err } // 將token的三個部分使用.進(jìn)行連接并返回 return HeaderAndPayload + "." + signature, nil }
解析Token
我們封裝一個解析token的方法
func ParseJwt(token string, key []byte) (*JWT, error) { // 分解規(guī)定,我們使用.進(jìn)行分隔,所以我們通過.進(jìn)行分隔成三個字符串的數(shù)組 jwtParts := strings.Split(token, ".") // 數(shù)據(jù)數(shù)組長度不是3就說明token在格式上就不合法 if len(jwtParts) != 3 { return nil, fmt.Errorf("非法token") } // 分別拿出 encodedHeader := jwtParts[0] encodedPayload := jwtParts[1] signature := jwtParts[2] // 使用key將token中的頭部和負(fù)載用.連接后進(jìn)行簽名 // 這個簽名應(yīng)該個token中第三部分的簽名一致 confirmSignature, err := generateSignature(key, []byte(encodedHeader+"."+encodedPayload)) if err != nil { return nil, fmt.Errorf("生成簽名錯誤") } // 如果不一致 if signature != confirmSignature { return nil, fmt.Errorf("token驗證失敗") } // 將payload解base64編碼 dstPayload, _ := base64.RawURLEncoding.DecodeString(encodedPayload) // 返回我們的JWT對象以供后續(xù)使用 return &JWT{encodedHeader, string(dstPayload), signature}, nil }
實際使用
我們構(gòu)造一個用戶的結(jié)構(gòu)體
type UserInfo struct { Name string `json:"name"` Password string `json:"password"` }
我們這次使用123456作為密鑰簡單的驗證一下
var Key []byte = []byte("12346")
在此我們構(gòu)造一個驗證的中間件
func jwtConfirm(context *gin.Context) { // 登錄不需要token if context.Request.RequestURI == "/login" { return } // 拿出token token := context.GetHeader("Token") // 進(jìn)行解析驗證 jwt, err := utils.ParseJwt(token, Key) if err != nil { context.JSON(200, gin.H{ "msg": err.Error(), }) // 有問題就流產(chǎn)掉(我也不知道怎么翻譯好了,香蕉貓.jpg) context.Abort() } // 驗證通過就將負(fù)載返回回去 context.JSON(200, gin.H{ "payload": jwt.Payload, }) }
我們在此基礎(chǔ)上就可以使用了,這邊使用gin框架簡單的測試一下
func main() { // 使用默認(rèn)路由 router := gin.Default() // 注冊中間件 router.Use(jwtConfirm) // 簡單做兩個服務(wù) router.POST("/login", func(context *gin.Context) { // 接收用戶參數(shù) var userInfo UserInfo = UserInfo{} // 使用jsonbind接收 bindErr := context.ShouldBindJSON(&userInfo) if bindErr != nil { context.JSON(200, gin.H{ "msg": bindErr.Error(), }) } // 使用密鑰做出token jwt, err := utils.CreateJwt(Key, userInfo) if err != nil { fmt.Println(err) } // 我們將token直接返回用于測試 context.JSON(200, gin.H{ "token": jwt, }) }) router.GET("/doing") router.Run() }
測試結(jié)果
我們拿到了token
我們現(xiàn)在去試一下如果不帶token的結(jié)果
我們試一下攜帶錯誤token的情況
我們最后測試一下正確的token
結(jié)語
在實際環(huán)境中會使用更復(fù)雜的情況進(jìn)行使用(例如密鑰會更加復(fù)雜,會在pyload中設(shè)置失效時間等等),但是生成token和解析token的操作和上述的操作差別不大
到此這篇關(guān)于golang原生實現(xiàn)JWT的示例代碼的文章就介紹到這了,更多相關(guān)golang原生實現(xiàn)JWT內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入探究Golang中l(wèi)og標(biāo)準(zhǔn)庫的使用
Go?語言標(biāo)準(zhǔn)庫中的?log?包設(shè)計簡潔明了,易于上手,可以輕松記錄程序運行時的信息、調(diào)試錯誤以及跟蹤代碼執(zhí)行過程中的問題等。本文主要來深入探究?log?包的使用和原理,幫助讀者更好地了解和掌握它2023-05-05Golang編程實現(xiàn)刪除字符串中出現(xiàn)次數(shù)最少字符的方法
這篇文章主要介紹了Golang編程實現(xiàn)刪除字符串中出現(xiàn)次數(shù)最少字符的方法,涉及Go語言字符串遍歷與運算相關(guān)操作技巧,需要的朋友可以參考下2017-01-01Go?語言數(shù)據(jù)結(jié)構(gòu)如何實現(xiàn)抄一個list示例詳解
這篇文章主要為大家介紹了Go?語言數(shù)據(jù)結(jié)構(gòu)如何實現(xiàn)抄一個list示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04