Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權詳解
前言
最近寫的項目中用到了JWT
鑒權,因此做個記錄
原先的jwt-go
倉庫已經(jīng)不再維護,遷移到了github.com/golang-jwt/jwt/v4
但是網(wǎng)上大多數(shù)還是v3
版本的使用教程,建議使用更加安全的v4
1.什么是JWT
JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸信息。特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業(yè)務邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。
2.JWT的數(shù)據(jù)結構
實際的JWT
由三部分組成,如下圖
中間用點(.
)分隔成三個部分。注意,JWT
內(nèi)部是沒有換行的,這里只是為了便于展示,將它寫成了幾行。JWT的三個部分依次如下:
Header
(頭部)Payload
(負載)Signature
(簽名)
寫成一行就是Header.Payload.Signature
2.1 Header
Header
部分是一個 JSON
對象,描述 JWT
的元數(shù)據(jù),通常是下面的樣子
{ "alg": "HS256", "typ": "JWT" }
上面代碼中,alg
屬性表示簽名的算法(algorithm
),默認是HMAC SHA256
(寫成 HS256
);typ
屬性表示這個令牌(token
)的類型(type
),JWT
令牌統(tǒng)一寫為JWT
。
將上面的 JSON
對象使用 Base64URL
算法(詳見后文)轉成字符串就成了第一部分Header
。
2.2 Payload
Payload
部分也是一個 JSON
對象,用來存放實際需要傳遞的數(shù)據(jù)。JWT
規(guī)定了7個官方字段,供選用。
iss (issuer)
:簽發(fā)人exp (expiration time)
:過期時間sub (subject)
:主題aud (audience)
:受眾nbf (Not Before)
:生效時間iat (Issued At)
:簽發(fā)時間jti (JWT ID)
:編號
我們還可以在這個部分自己定義字段,下面就是一個例子
{ "sub": "1234567890", "name": "John Doe", "admin": true }
注意,JWT
默認是不加密的,任何人都可以讀到,所以不要把秘密信息放在這個部分。
這個 JSON
對象也要使用 Base64URL
算法轉成字符串。
2.3 Signature
Signature
部分是對前兩部分的簽名,防止數(shù)據(jù)篡改。
首先,需要指定一個密鑰(secret
)。這個密鑰只有服務器才知道,不能泄露給用戶。然后,使用 Header
里面指定的簽名算法(默認是 HMAC SHA256
),按照下面的公式產(chǎn)生簽名。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
2.4 Base64URL
前面提到,Header
和 Payload
串型化的算法是 Base64URL
。這個算法跟 Base64
算法基本類似,但有一些小的不同。
JWT
作為一個令牌(token
),有些場合可能會放到 URL
(比如 api.example.com/?token=xxx)。Base64
有三個字符+,/和=,在 URL
里面有特殊含義,所以要被替換掉:=被省略、+替換成-,/替換成_ 。這就是 Base64URL
算法。
算出簽名以后,把 Header
、Payload
、Signature
三個部分拼成一個字符串,每個部分之間用"點"(.)分隔,就可以返回給用戶。
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,后面會用到
生成token
// 這里傳入的是手機號,因為我項目登陸用的是手機號和密碼 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))), // 過期時間3小時 IssuedAt: jwt.NewNumericDate(time.Now()), // 簽發(fā)時間 NotBefore: jwt.NewNumericDate(time.Now()), // 生效時間 }} 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") }
參考:
總結
到此這篇關于Go語言如何使用golang-jwt/jwt/v4進行JWT鑒權的文章就介紹到這了,更多相關Go語言進行JWT鑒權內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Golang timer可能造成的內(nèi)存泄漏問題分析
本文探討了Golang中timer可能造成的內(nèi)存泄漏問題,通過分析一段代碼,解釋了為什么協(xié)程在調用timer.Stop()后無法正常退出,文章指出,timer.Stop()并不關閉Channel,導致協(xié)程無法繼續(xù)執(zhí)行,最后,提出了一種修復方法,并呼吁大家關注和分享2024-12-12golang socket斷點續(xù)傳大文件的實現(xiàn)方法
今天小編就為大家分享一篇golang socket斷點續(xù)傳大文件的實現(xiàn)方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07Go Grpc Gateway兼容HTTP協(xié)議文檔自動生成網(wǎng)關
這篇文章主要為大家介紹了Go Grpc Gateway兼容HTTP協(xié)議文檔自動生成網(wǎng)關示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06