網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
前言
最近寫的項(xiàng)目中用到了JWT
鑒權(quán),因此做個(gè)記錄
原先的jwt-go
倉(cāng)庫(kù)已經(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的聲明一般被用來(lái)在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源,也可以增加一些額外的其它業(yè)務(wù)邏輯所必須的聲明信息,該token也可直接被用于認(rèn)證,也可被加密。
2.JWT的數(shù)據(jù)結(jié)構(gòu)
實(shí)際的JWT
由三部分組成,如下圖
中間用點(diǎn)(.
)分隔成三個(gè)部分。注意,JWT
內(nèi)部是沒(mé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
算法(詳見(jiàn)后文)轉(zhuǎn)成字符串就成了第一部分Header
。
2.2 Payload
Payload
部分也是一個(gè) JSON
對(duì)象,用來(lái)存放實(shí)際需要傳遞的數(shù)據(jù)。JWT
規(guī)定了7個(gè)官方字段,供選用。
-
iss (issuer)
:簽發(fā)人 -
exp (expiration time)
:過(guò)期時(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))), // 過(guò)期時(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") }
參考:
JSON Web Token 入門教程
總結(jié)
原文鏈接:https://blog.csdn.net/weixin_44294408/article/details/122095919
相關(guān)推薦
- 2022-09-08 pytorch中Tensor.to(device)和model.to(device)的區(qū)別及說(shuō)明_p
- 2022-10-18 Golang?內(nèi)存管理簡(jiǎn)單技巧詳解_Golang
- 2022-05-11 使用Redission實(shí)現(xiàn)分布式鎖
- 2022-11-11 Python?第三方庫(kù)?Pandas?數(shù)據(jù)分析教程_python
- 2023-11-13 【云原生】docker設(shè)置非root用戶使用權(quán)限的方法
- 2023-01-15 Android開發(fā)可添加頭尾的RecycleView的實(shí)現(xiàn)_Android
- 2023-04-11 利用Matlab實(shí)現(xiàn)時(shí)域分析功能的示例詳解_C 語(yǔ)言
- 2024-01-11 String.valueOf() 方法的使用
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支