Go語言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)詳解
前言
最近寫的項目中用到了JWT鑒權(quán),因此做個記錄
原先的jwt-go倉庫已經(jīng)不再維護(hù),遷移到了github.com/golang-jwt/jwt/v4
但是網(wǎng)上大多數(shù)還是v3版本的使用教程,建議使用更加安全的v4
1.什么是JWT
JSON Web Token (JWT)是一個開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸信息。特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認(rèn)證,也可被加密。
2.JWT的數(shù)據(jù)結(jié)構(gòu)
實際的JWT由三部分組成,如下圖

中間用點(.)分隔成三個部分。注意,JWT 內(nèi)部是沒有換行的,這里只是為了便于展示,將它寫成了幾行。JWT的三個部分依次如下:
Header(頭部)Payload(負(fù)載)Signature(簽名)
寫成一行就是Header.Payload.Signature

2.1 Header
Header 部分是一個 JSON 對象,描述 JWT 的元數(shù)據(jù),通常是下面的樣子
{
"alg": "HS256",
"typ": "JWT"
}
上面代碼中,alg屬性表示簽名的算法(algorithm),默認(rèn)是HMAC SHA256(寫成 HS256);typ屬性表示這個令牌(token)的類型(type),JWT 令牌統(tǒng)一寫為JWT。
將上面的 JSON 對象使用 Base64URL 算法(詳見后文)轉(zhuǎn)成字符串就成了第一部分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 默認(rèn)是不加密的,任何人都可以讀到,所以不要把秘密信息放在這個部分。
這個 JSON 對象也要使用 Base64URL 算法轉(zhuǎn)成字符串。
2.3 Signature
Signature 部分是對前兩部分的簽名,防止數(shù)據(jù)篡改。
首先,需要指定一個密鑰(secret)。這個密鑰只有服務(wù)器才知道,不能泄露給用戶。然后,使用 Header 里面指定的簽名算法(默認(rèn)是 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
// 這里傳入的是手機(jī)號,因為我項目登陸用的是手機(jī)號和密碼
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")
}
參考:
總結(jié)
到此這篇關(guān)于Go語言如何使用golang-jwt/jwt/v4進(jìn)行JWT鑒權(quán)的文章就介紹到這了,更多相關(guān)Go語言進(jìn)行JWT鑒權(quán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Golang實現(xiàn)Excel表格的導(dǎo)入導(dǎo)出功能
最近項目開發(fā)中有涉及到Excel的導(dǎo)入與導(dǎo)出功能,特別是導(dǎo)出表格時需要特定的格式,所以本文給大家介紹了基于Golang實現(xiàn)Excel表格的導(dǎo)入導(dǎo)出功能,文中通過代碼示例和圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
Go調(diào)度器學(xué)習(xí)之系統(tǒng)調(diào)用詳解
這篇文章腫,將以一個簡單的文件打開的系統(tǒng)調(diào)用,來分析一下Go調(diào)度器在系統(tǒng)調(diào)用時做了什么。文中的示例代碼講解詳細(xì),需要的可以參考一下2023-04-04

