Go語言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)詳解
前言
最近寫的項(xiàng)目中用到了JWT
鑒權(quán),因此做個(gè)記錄
原先的jwt-go
倉(cāng)庫已經(jīng)不再維護(hù),遷移到了github.com/golang-jwt/jwt/v4
但是網(wǎng)上大多數(shù)還是v3
版本的使用教程,建議使用更加安全的v4
1.什么是JWT
JSON Web Token (JWT)是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對(duì)象在各方之間安全地傳輸信息。特別適用于分布式站點(diǎn)的單點(diǎn)登錄(SSO)場(chǎng)景。JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認(rèn)證,也可被加密。
2.JWT的數(shù)據(jù)結(jié)構(gòu)
實(shí)際的JWT
由三部分組成,如下圖
中間用點(diǎn)(.
)分隔成三個(gè)部分。注意,JWT
內(nèi)部是沒有換行的,這里只是為了便于展示,將它寫成了幾行。JWT的三個(gè)部分依次如下:
Header
(頭部)Payload
(負(fù)載)Signature
(簽名)
寫成一行就是Header.Payload.Signature
2.1 Header
Header
部分是一個(gè) JSON
對(duì)象,描述 JWT
的元數(shù)據(jù),通常是下面的樣子
{ "alg": "HS256", "typ": "JWT" }
上面代碼中,alg
屬性表示簽名的算法(algorithm
),默認(rèn)是HMAC SHA256
(寫成 HS256
);typ
屬性表示這個(gè)令牌(token
)的類型(type
),JWT
令牌統(tǒng)一寫為JWT
。
將上面的 JSON
對(duì)象使用 Base64URL
算法(詳見后文)轉(zhuǎn)成字符串就成了第一部分Header
。
2.2 Payload
Payload
部分也是一個(gè) JSON
對(duì)象,用來存放實(shí)際需要傳遞的數(shù)據(jù)。JWT
規(guī)定了7個(gè)官方字段,供選用。
iss (issuer)
:簽發(fā)人exp (expiration time)
:過期時(shí)間sub (subject)
:主題aud (audience)
:受眾nbf (Not Before)
:生效時(shí)間iat (Issued At)
:簽發(fā)時(shí)間jti (JWT ID)
:編號(hào)
我們還可以在這個(gè)部分自己定義字段,下面就是一個(gè)例子
{ "sub": "1234567890", "name": "John Doe", "admin": true }
注意,JWT
默認(rèn)是不加密的,任何人都可以讀到,所以不要把秘密信息放在這個(gè)部分。
這個(gè) JSON
對(duì)象也要使用 Base64URL
算法轉(zhuǎn)成字符串。
2.3 Signature
Signature
部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改。
首先,需要指定一個(gè)密鑰(secret
)。這個(gè)密鑰只有服務(wù)器才知道,不能泄露給用戶。然后,使用 Header
里面指定的簽名算法(默認(rèn)是 HMAC SHA256
),按照下面的公式產(chǎn)生簽名。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2.4 Base64URL
前面提到,Header
和 Payload
串型化的算法是 Base64URL
。這個(gè)算法跟 Base64
算法基本類似,但有一些小的不同。
JWT
作為一個(gè)令牌(token
),有些場(chǎng)合可能會(huì)放到 URL
(比如 api.example.com/?token=xxx)。Base64
有三個(gè)字符+,/和=,在 URL
里面有特殊含義,所以要被替換掉:=被省略、+替換成-,/替換成_ 。這就是 Base64URL
算法。
算出簽名以后,把 Header
、Payload
、Signature
三個(gè)部分拼成一個(gè)字符串,每個(gè)部分之間用"點(diǎn)"(.)分隔,就可以返回給用戶。
3使用JWT
安裝
go install "github.com/golang-jwt/jwt/v4"
生成Token
定義claims
和serect
type MyClaims struct { Phone string `json:"phone"` jwt.RegisteredClaims // 注意!這是jwt-go的v4版本新增的,原先是jwt.StandardClaims } var MySecret = []byte("手寫的從前") // 定義secret,后面會(huì)用到
生成token
// 這里傳入的是手機(jī)號(hào),因?yàn)槲翼?xiàng)目登陸用的是手機(jī)號(hào)和密碼 func MakeToken(phone string) (tokenString string, err error) { claim := MyClaims{ Phone: phone, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(time.Now().Add(3 * time.Hour * time.Duration(1))), // 過期時(shí)間3小時(shí) IssuedAt: jwt.NewNumericDate(time.Now()), // 簽發(fā)時(shí)間 NotBefore: jwt.NewNumericDate(time.Now()), // 生效時(shí)間 }} token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim) // 使用HS256算法 tokenString, err = token.SignedString(MySecret) return tokenString, err }
解析token
func Secret() jwt.Keyfunc { return func(token *jwt.Token) (interface{}, error) { return []byte("手寫的從前"), nil // 這是我的secret } } func ParseToken(tokenss string) (*MyClaims, error) { token, err := jwt.ParseWithClaims(tokenss, &MyClaims{}, Secret()) if err != nil { if ve, ok := err.(*jwt.ValidationError); ok { if ve.Errors&jwt.ValidationErrorMalformed != 0 { return nil, errors.New("that's not even a token") } else if ve.Errors&jwt.ValidationErrorExpired != 0 { return nil, errors.New("token is expired") } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { return nil, errors.New("token not active yet") } else { return nil, errors.New("couldn't handle this token") } } } if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { return claims, nil } return nil, errors.New("couldn't handle this token") }
參考:
總結(jié)
到此這篇關(guān)于Go語言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)的文章就介紹到這了,更多相關(guān)Go語言進(jìn)行JWT鑒權(quán)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go實(shí)現(xiàn)socks5服務(wù)器的方法
SOCKS5 是一個(gè)代理協(xié)議,它在使用TCP/IP協(xié)議通訊的前端機(jī)器和服務(wù)器機(jī)器之間扮演一個(gè)中介角色,使得內(nèi)部網(wǎng)中的前端機(jī)器變得能夠訪問Internet網(wǎng)中的服務(wù)器,或者使通訊更加安全,這篇文章主要介紹了Go實(shí)現(xiàn)socks5服務(wù)器的方法,需要的朋友可以參考下2023-07-07Golang timer可能造成的內(nèi)存泄漏問題分析
本文探討了Golang中timer可能造成的內(nèi)存泄漏問題,通過分析一段代碼,解釋了為什么協(xié)程在調(diào)用timer.Stop()后無法正常退出,文章指出,timer.Stop()并不關(guān)閉Channel,導(dǎo)致協(xié)程無法繼續(xù)執(zhí)行,最后,提出了一種修復(fù)方法,并呼吁大家關(guān)注和分享2024-12-12golang?http請(qǐng)求未釋放造成的錯(cuò)誤問題
這篇文章主要介紹了golang?http請(qǐng)求未釋放造成的錯(cuò)誤問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01golang socket斷點(diǎn)續(xù)傳大文件的實(shí)現(xiàn)方法
今天小編就為大家分享一篇golang socket斷點(diǎn)續(xù)傳大文件的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-07-07Go Grpc Gateway兼容HTTP協(xié)議文檔自動(dòng)生成網(wǎng)關(guān)
這篇文章主要為大家介紹了Go Grpc Gateway兼容HTTP協(xié)議文檔自動(dòng)生成網(wǎng)關(guān)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06