golang中的jwt使用教程流程分析
golang-jwt使用
老版本<v4.0.0 為github.com/dgrijalva/jwt-go 新版本https://github.com/golang-jwt/jwt
本文環(huán)境為新版本
加密
1.在使用之前我們應(yīng)該對(duì)它進(jìn)行安裝與導(dǎo)入
go get -u github.com/golang-jwt/jwt/v4 import "github.com/golang-jwt/jwt/v4"
2.既然導(dǎo)入成功那就開始使用吧
package main import ( "fmt" "github.com/golang-jwt/jwt/v4" ) func main() { // 創(chuàng)建秘鑰 key := []byte("aaa") // 創(chuàng)建Token結(jié)構(gòu)體 claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "user": "zhangshan", "pass": "123123", }) // 調(diào)用加密方法,發(fā)揮Token字符串 signingString, err := claims.SignedString(key) if err != nil { return } fmt.Println(signingString) } //這邊是輸出結(jié)果 &{ 0xc0000c2690 map[alg:ES256 typ:JWT] map[user:zhangshan] false} // 這是加密后的字符串 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzIjoiMTIzMTIzIiwidXNlciI6InpoYW5nc2hhbiJ9.-2-xIJXMGKV-GyhM24OKbDVqWs4dsIANBsGhzXEfEFM
3.逐步講解
首先我們先查看第一步
claims := jwt.NewWithClaims(jwt.SigningMethodES256, jwt.MapClaims{ "user": "zhangshan", })
newWithClaims會(huì)返回一個(gè)Token結(jié)構(gòu)體,而這個(gè)token結(jié)構(gòu)體有以下屬性
type Token struct { Raw string //原始令牌 Method SigningMethod // 加密方法 比如sha256加密 Header map[string]interface{} // token頭信息 Claims Claims // 加密配置,比如超時(shí)時(shí)間等 Signature string // 加密后的字符串 Valid bool // 是否校驗(yàn) } type Token struct { Raw string //原始令牌 Method SigningMethod // 加密方法 比如sha256加密 Header map[string]interface{} // token頭信息 Claims Claims // 加密配置,比如超時(shí)時(shí)間等 Signature string // 加密后的字符串 Valid bool // 是否校驗(yàn) }
我們可以通過(guò)該結(jié)構(gòu)體獲取到加密后的字符串信息。
接下來(lái)我們需要講解一下Claims該結(jié)構(gòu)體存儲(chǔ)了token字符串的超時(shí)時(shí)間等信息以及在解析時(shí)的Token校驗(yàn)工作。
type Claims interface { Valid() error } //實(shí)現(xiàn)類有MapClaims、RegisteredClaims、StandardClaims(舍棄) //其實(shí)后兩個(gè)結(jié)構(gòu)體都是根據(jù)MapClaims編寫而來(lái),所以我們只需要掌握MapClaims即可 type MapClaims map[string]interface{}
就是一個(gè)map集合,但是它實(shí)現(xiàn)了上面Valid()方法,該方法里面實(shí)現(xiàn)了對(duì)token過(guò)期日期校驗(yàn)、發(fā)布時(shí)間、生效時(shí)間的校驗(yàn)工作。
所以在map里面有三個(gè)固定的鍵我們可以根據(jù)需要進(jìn)行設(shè)置,exp 過(guò)期時(shí)間、iat 發(fā)布時(shí)間、nbf 生效時(shí)間
解密
既然已經(jīng)將Token值進(jìn)行了加密那么如何對(duì)其進(jìn)行驗(yàn)證(俗稱解密)那?
// 根據(jù)Token字符串解析成Claims結(jié)構(gòu)體 _, err = jwt.ParseWithClaims(signingString, jwt.MapClaims{}, func(token *jwt.Token) (interface{}, error) { fmt.Println(token.Header) return []byte("aaa"), nil }) if err != nil { fmt.Println(err) return }
在該方法中,有四個(gè)個(gè)參數(shù),我們需要注意第三個(gè)方法參數(shù),該類型是一個(gè)方法,token作為參數(shù),兩個(gè)返回值,我們重點(diǎn)關(guān)注第一個(gè)返回值,該值會(huì)用來(lái)進(jìn)行編碼解析,所以我們需要傳入上文中的key秘鑰。
第四個(gè)參數(shù)為配置參數(shù),主要控制parse過(guò)程中對(duì)token的校驗(yàn)工作,比如調(diào)用WithoutClaimsValidation()則會(huì)關(guān)閉token的過(guò)期檢查等操作。
WithValidMethods(methods []string) //指定使用的解密算法,他會(huì)跟token中加密方法進(jìn)行名稱比較,如果false則返回錯(cuò)誤值 WithoutClaimsValidation() // 忽略過(guò)期、發(fā)布時(shí)間等檢查
源碼分析
接下來(lái)我們將講解一下具體流程
SignedString
SignedString用來(lái)生成token結(jié)構(gòu)體
func (t *Token) SignedString(key interface{}) (string, error) { var sig, sstr string var err error // 通過(guò)base64 對(duì)header與claims進(jìn)行加密 if sstr, err = t.SigningString(); err != nil { return "", err } // 通過(guò)指定的加密方法,根據(jù)key值進(jìn)行加密 if sig, err = t.Method.Sign(sstr, key); err != nil { return "", err } // 拼接token字符串 return strings.Join([]string{sstr, sig}, "."), nil }
ParseWithClaims
ParseWithClaims用來(lái)解析Token字符串返回token結(jié)構(gòu)體
func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc, options ...ParserOption) (*Token, error) { // 創(chuàng)建解析器, //ParseWithClaims 解析token字符串 return NewParser(options...).ParseWithClaims(tokenString, claims, keyFunc) } func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { // 解析字符串,將根據(jù).進(jìn)行切割,通過(guò)base64進(jìn)行解碼,根據(jù)header中的alg屬性獲取加密方法比如sha256 // 返回值token為Token結(jié)構(gòu)體,parts為字符串切割后的數(shù)組 token, parts, err := p.ParseUnverified(tokenString, claims) if err != nil { return token, err } // 判斷是否指定校驗(yàn)方法 if p.ValidMethods != nil { var signingMethodValid = false var alg = token.Method.Alg() for _, m := range p.ValidMethods { if m == alg { signingMethodValid = true break } } if !signingMethodValid { // 指定方法與token中的方法不一致 return token, NewValidationError(fmt.Sprintf("signing method %v is invalid", alg), ValidationErrorSignatureInvalid) } } // 獲取key秘鑰 var key interface{} // 判斷是否實(shí)現(xiàn)keyfunc,就是第三個(gè)參數(shù) if keyFunc == nil { // keyFunc was not provided. short circuiting validation return token, NewValidationError("no Keyfunc was provided.", ValidationErrorUnverifiable) } // 調(diào)用方法,返回key值 if key, err = keyFunc(token); err != nil { // keyFunc returned an error if ve, ok := err.(*ValidationError); ok { return token, ve } return token, &ValidationError{Inner: err, Errors: ValidationErrorUnverifiable} } vErr := &ValidationError{} // 判斷是否進(jìn)行校驗(yàn),SkipClaimsValidation默認(rèn)為false 加上!成為true if !p.SkipClaimsValidation { if err := token.Claims.Valid(); err != nil { // If the Claims Valid returned an error, check if it is a validation error, // If it was another error type, create a ValidationError with a generic ClaimsInvalid flag set if e, ok := err.(*ValidationError); !ok { vErr = &ValidationError{Inner: err, Errors: ValidationErrorClaimsInvalid} } else { vErr = e } } } // 進(jìn)行簽名驗(yàn)證 token.Signature = parts[2] if err = token.Method.Verify(strings.Join(parts[0:2], "."), token.Signature, key); err != nil { vErr.Inner = err vErr.Errors |= ValidationErrorSignatureInvalid } if vErr.valid() { token.Valid = true return token, nil } return token, vErr }
到此這篇關(guān)于golang中的jwt使用教程的文章就介紹到這了,更多相關(guān)golang jwt使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Golang實(shí)現(xiàn)JWT身份驗(yàn)證的示例詳解
- golang原生實(shí)現(xiàn)JWT的示例代碼
- Golang使用JWT進(jìn)行認(rèn)證和加密的示例詳解
- Go語(yǔ)言學(xué)習(xí)之golang-jwt/jwt的教程分享
- golang中g(shù)in框架接入jwt使用token驗(yàn)證身份
- 基于gin的golang web開發(fā)之認(rèn)證利器jwt
- golang jwt+token驗(yàn)證的實(shí)現(xiàn)
- golang之JWT實(shí)現(xiàn)的示例代碼
- golang整合jwt的實(shí)現(xiàn)示例
相關(guān)文章
golang 使用time包獲取時(shí)間戳與日期格式化操作
這篇文章主要介紹了golang 使用time包獲取時(shí)間戳與日期格式化操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12golang中兩個(gè)協(xié)程交替打印數(shù)字和字母的實(shí)現(xiàn)
這篇文章給大家介紹了golang中兩個(gè)協(xié)程交替打印數(shù)字和字母的實(shí)現(xiàn),文中通過(guò)代碼示例講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01詳解如何在Go語(yǔ)言中循環(huán)數(shù)據(jù)結(jié)構(gòu)
這篇文章主要為大家詳細(xì)介紹了如何在Go語(yǔ)言中循環(huán)數(shù)據(jù)結(jié)構(gòu)(循環(huán)字符串、循環(huán)map結(jié)構(gòu)和循環(huán)Struct),文中的示例代碼代碼講解詳細(xì),需要的可以參考一下2022-10-10go redis實(shí)現(xiàn)滑動(dòng)窗口限流的方式(redis版)
這篇文章主要介紹了go redis實(shí)現(xiàn)滑動(dòng)窗口限流的方式(redis版),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12淺析如何利用Go的plugin機(jī)制實(shí)現(xiàn)熱更新
熱更新,或稱熱重載或動(dòng)態(tài)更新,是一種軟件更新技術(shù),允許程序在運(yùn)行時(shí),不停機(jī)更新代碼或資源,本文主要來(lái)討論下GO語(yǔ)言是否可以利用plugin機(jī)制實(shí)現(xiàn)熱更新,感興趣的可以了解下2024-04-04Golang中基礎(chǔ)的命令行模塊urfave/cli的用法說(shuō)明
這篇文章主要介紹了Golang中基礎(chǔ)的命令行模塊urfave/cli的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12