淺談JWT在GO中的使用方法及原理
1. JWT是什么
JWT(JSON Web Token) 是一種基于 JSON 的開放標(biāo)準(zhǔn),用于在網(wǎng)絡(luò)應(yīng)用間傳遞聲明。JWT被設(shè)計(jì)為可安全地將用戶身份驗(yàn)證和授權(quán)數(shù)據(jù)作為 JSON 對象在各個(gè)應(yīng)用程序之間傳遞。
JWT 主要由三部分組成:Header
,Payload
和Signature
。
Header 包含了兩部分信息:令牌的類型(即 JWT)和所使用的算法,通常采用的算法是 HMAC SHA256 或 RSA。
Payload(載荷)包含了要傳遞的信息,可以包括用戶 ID、用戶角色、過期時(shí)間等信息。
Signature(簽名)是使用私鑰對 Header 和 Payload 進(jìn)行簽名生成的,用來驗(yàn)證消息確實(shí)是由發(fā)送方發(fā)出的,以及在傳輸過程中沒有被篡改過。
JWT 的優(yōu)點(diǎn)包括:
- 無狀態(tài):JWT 本身就包含了用戶信息,不需要再去查詢數(shù)據(jù)庫或者其他的存儲設(shè)備。
- 安全性:由于JWT包含了簽名,所以一旦JWT被篡改,接收方就能夠檢測到。
- 便捷性:JWT 的格式是輕量級的,容易傳輸,可以通過 URL、POST 參數(shù)或者在HTTP header中發(fā)送。
使用 JWT 的過程可以分為以下幾個(gè)步驟:
- 在服務(wù)器端生成一個(gè) JWT,包括 Header、Payload 和 Signature。
- 在需要驗(yàn)證用戶身份的請求中,將 JWT 添加到 HTTP header 中。
- 服務(wù)器收到請求后,從 HTTP header 中提取 JWT,并對其進(jìn)行驗(yàn)證,包括簽名驗(yàn)證、Payload 中的信息驗(yàn)證等。
- 如果驗(yàn)證成功,服務(wù)器返回請求所需的數(shù)據(jù)。
- 如果驗(yàn)證失敗,則拒絕請求。
JWT 是一種非常流行的身份驗(yàn)證和授權(quán)機(jī)制,被廣泛應(yīng)用于各種互聯(lián)網(wǎng)應(yīng)用中。
2. GO生成JWT
?package jwt ?? ?import ( ? "github.com/dgrijalva/jwt-go" ? "myWeb/config" ? "time" ?) ?? ?type Claims struct { ? ID ? ? ? int64 ?`json:"id"` ? Username string `json:"username"` ? jwt.StandardClaims ?} ?? ?// 生成 token ?? ?func GenerateToken(id int64 ,username string) (string, error) { ? // 定義 token 的過期時(shí)間 ? expireTime := time.Now().Add(config.ExpireDuration).Unix() ?? ? // 創(chuàng)建一個(gè)自定義的 Claims ? claims := &Claims{ ? ? ? ? ?ID:id, ? Username: username, ? StandardClaims: jwt.StandardClaims{ ? ExpiresAt: expireTime, ? IssuedAt: ?time.Now().Unix(), ? Issuer: ? ?"pogf", ? }, ? } ?? ? // 使用 JWT 簽名算法生成 token ? token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) ?? ? // 將 token 進(jìn)行加鹽加密 ? tokenString, err := token.SignedString(config.JwtKey) ? if err != nil { ? return "", err ? } ?? ? return tokenString, nil ?} ??
詳細(xì)分析:
?type Claims struct { ? ID ? ? ? int64 ?`json:"id"` ? Username string `json:"username"` ? jwt.StandardClaims ?}
該結(jié)構(gòu)體用于定義 JWT 的 payload,也就是 JWT 載荷中存儲的信息。其中,ID
和 Username
用于標(biāo)識用戶身份,jwt.StandardClaims
則是 JWT 的標(biāo)準(zhǔn)聲明,包含了 JWT 的一些基本信息,比如過期時(shí)間、簽發(fā)時(shí)間等。在創(chuàng)建 JWT 時(shí),我們需要將這個(gè)結(jié)構(gòu)體傳入,以便生成 JWT 的 payload。在驗(yàn)證 JWT 時(shí),我們也需要解析出這個(gè)結(jié)構(gòu)體,以便獲取 JWT 中存儲的用戶身份信息。
?expireTime := time.Now().Add(config.ExpireDuration).Unix()
這行代碼的作用是根據(jù)配置文件中的過期時(shí)間(config.ExpireDuration
)計(jì)算出當(dāng)前時(shí)間加上過期時(shí)間后的 Unix 時(shí)間戳(expireTime
),以便在生成 JWT 時(shí)設(shè)置過期時(shí)間。
time.Now()
函數(shù)返回當(dāng)前的本地時(shí)間(time.Time 類型),Add()
方法則用于對時(shí)間進(jìn)行加減,參數(shù)是 time.Duration
類型,表示時(shí)間間隔。因此,time.Now().Add(config.ExpireDuration)
計(jì)算出的是過期時(shí)間的時(shí)間點(diǎn)。接著,調(diào)用 Unix()
方法將時(shí)間點(diǎn)轉(zhuǎn)換為對應(yīng)的 Unix 時(shí)間戳(int64 類型),用于設(shè)置 JWT 的過期時(shí)間。
? claims := &Claims{ ? ? ? ? ?ID:id, ? Username: username, ? StandardClaims: jwt.StandardClaims{ ? ExpiresAt: expireTime, ? IssuedAt: ?time.Now().Unix(), ? Issuer: ? ?"pogf", ? }, ? }
這段代碼是在創(chuàng)建一個(gè)包含用戶身份信息的JWT token,其中Claims
結(jié)構(gòu)體定義了JWT token中所包含的信息,包括ID
和Username
,以及jwt.StandardClaims
結(jié)構(gòu)體中的標(biāo)準(zhǔn)信息,如ExpiresAt
(過期時(shí)間),IssuedAt
(簽發(fā)時(shí)間)和Issuer
(簽發(fā)者)等。
在上述代碼中,ID
和Username
分別代表用戶的唯一標(biāo)識和用戶名,這些信息將被編碼到JWT token中。StandardClaims
中的信息則用于控制JWT token的生命周期和有效性。
ExpiresAt
表示JWT token的過期時(shí)間,超過這個(gè)時(shí)間后,JWT token將失效,無法再被使用。IssuedAt
表示JWT token的簽發(fā)時(shí)間,Issuer
表示JWT token的簽發(fā)者,這些信息可以幫助驗(yàn)證JWT token的合法性。
?token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
它首先創(chuàng)建了一個(gè) JWT 對象 token
,其中包含了指定的簽名方法 jwt.SigningMethodHS256
和聲明 claims
。
JWT 中有三個(gè)部分:頭部(Header)、載荷(Payload)和簽名(Signature)。頭部指定了所使用的簽名算法,例如 HS256
表示使用 HMAC-SHA256 算法進(jìn)行簽名。載荷是 JWT 中用來攜帶實(shí)際信息的部分,其中可以自定義各種聲明信息,例如上面代碼中的 claims
變量。簽名是將頭部和載荷進(jìn)行加密得到的一串字符串,用于驗(yàn)證 JWT 是否合法。
因此,這段代碼就是創(chuàng)建了一個(gè)帶有指定聲明的 JWT 對象,并指定了使用 HS256 算法進(jìn)行簽名。
? // 將 token 進(jìn)行加鹽加密 ? tokenString, err := token.SignedString(config.JwtKey) ? if err != nil { ? return "", err ? } ? return tokenString, nil
加鹽加密的目的是為了增加數(shù)據(jù)的安全性,防止攻擊者使用彩虹表等方式對加密后的數(shù)據(jù)進(jìn)行破解。加鹽是指在原始數(shù)據(jù)的基礎(chǔ)上加上一些隨機(jī)的字符串或數(shù)字,使得同樣的原始數(shù)據(jù)加鹽后的結(jié)果是不同的。加密是指將原始數(shù)據(jù)和鹽一起通過某種加密算法進(jìn)行加密,得到一串密文。密文是不能被破解的,只能通過使用同樣的鹽和加密算法對原始數(shù)據(jù)進(jìn)行加密后得到相同的密文來驗(yàn)證數(shù)據(jù)的真實(shí)性。
在JWT中,加鹽加密可以有效地防止攻擊者偽造token,從而保障應(yīng)用的安全性。具體地,JWT在生成token時(shí)會使用指定的秘鑰對payload進(jìn)行簽名,這個(gè)秘鑰就是加鹽的一部分。只有使用相同的秘鑰才能對payload進(jìn)行解密并驗(yàn)證token的真實(shí)性。因此,只有知道秘鑰的人才能生成有效的token,從而有效地保護(hù)了應(yīng)用的安全性。
單元測試
?func TestGenerateToken(t *testing.T) { ? token, err := GenerateToken(1, "wyf") ? if err != nil { ? t.Fatal(err) ? } ? t.Logf(token) ?} ??
?$ go test -v -run TestGenerateToken ?=== RUN ? TestGenerateToken ? ? jwt_test.go:10: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJ3eWYiLCJleHAiOjE2ODM4NzU4NjcsImlhdCI6MTY4Mzc4OTQ2NywiaXNzIjoicG9nZiJ9.rXzf1fzidsfwe4HRBt7JN_NxAxUceD0HxdpCQsbPuFc ?--- PASS: TestGenerateToken (0.00s) ?PASS ?ok ? ? myWeb/util ? ? ?0.058s ??
3. GO解析JWT
相關(guān)函數(shù)介紹
?func ParseToken(tokenString string) (*Claims, error) { ? // 解析 token ? token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) { ? return config.JwtKey, nil ? }) ?? ? if err != nil { ? return nil, err ? } ?? ? if claims, ok := token.Claims.(*Claims); ok && token.Valid { ? return claims, nil ? } else { ? return nil, jwt.NewValidationError("invalid token", jwt.ValidationErrorClaimsInvalid) ? } ?} ??
?func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token, error) { ? return new(Parser).ParseWithClaims(tokenString, claims, keyFunc) ?}
jwt.ParseWithClaims()
函數(shù)用于解析并驗(yàn)證JWT token,并提取出其中的Claims數(shù)據(jù)結(jié)構(gòu)。該函數(shù)接受三個(gè)參數(shù):
tokenString
: 要解析的JWT token字符串。claims
: 一個(gè)結(jié)構(gòu)體指針,用于接收從JWT token中解析出來的Claims數(shù)據(jù)。keyFunc
: 一個(gè)回調(diào)函數(shù),用于驗(yàn)證JWT token的簽名。在函數(shù)內(nèi)部,可以對JWT token的簽名進(jìn)行驗(yàn)證,比如檢查簽名是否正確、是否過期等等。該函數(shù)需要返回一個(gè)interface{}類型的值,表示用于驗(yàn)證簽名的密鑰。如果驗(yàn)證成功,應(yīng)該返回一個(gè)非空的密鑰;如果驗(yàn)證失敗,應(yīng)該返回一個(gè)nil值和相應(yīng)的錯(cuò)誤信息。
在上述代碼中,&Claims{}
作為第二個(gè)參數(shù)傳遞給了jwt.ParseWithClaims()
函數(shù),這表示從JWT token中解析出的Claims數(shù)據(jù)將被解碼為該結(jié)構(gòu)體類型。第三個(gè)參數(shù)是一個(gè)匿名函數(shù),用于驗(yàn)證JWT token的簽名,config.JwtKey
被作為用于驗(yàn)證簽名的密鑰傳遞。如果JWT token驗(yàn)證通過,jwt.ParseWithClaims()
函數(shù)將返回一個(gè)*jwt.Token
類型的指針,其中包含了解碼后的Claims數(shù)據(jù),以及一些其他的元數(shù)據(jù)。如果驗(yàn)證失敗,函數(shù)將返回相應(yīng)的錯(cuò)誤信息。
單元測試
?func TestParseToken(t *testing.T) { ? c, err := ParseToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJ3eWYiLCJleHAiOjE2ODM4NzU4NjcsImlhdCI6MTY4Mzc4OTQ2NywiaXNzIjoicG9nZiJ9.rXzf1fzidsfwe4HRBt7JN_NxAxUceD0HxdpCQsbPuFc") ? if err != nil { ? t.Fatal(err) ? } ? t.Log(*c) ?}
?$ go test -v -run TestParseToken ?=== RUN ? TestParseToken ? ? jwt_test.go:18: {1 wyf { 1683875867 ?1683789467 pogf 0 }} ?--- PASS: TestParseToken (0.00s) ?PASS ?ok ? ? myWeb/util ? ? ?0.796s
4. 總結(jié)
JWT(JSON Web Token)是一種用于身份驗(yàn)證的開放標(biāo)準(zhǔn),它通過在用戶和服務(wù)器之間傳遞被加密的 JSON 對象來安全地傳輸信息。JWT 由三個(gè)部分組成:頭部、載荷和簽名。其中,頭部包含加密算法和 token 類型等信息,載荷包含存儲在 token 中的用戶信息,簽名用于驗(yàn)證 token 的真實(shí)性和完整性。
使用 JWT 時(shí)需要注意以下幾點(diǎn):
- 避免在 JWT 中存儲敏感信息,比如密碼、銀行卡號等。
- 需要使用安全的算法來簽名和加密 JWT,比如使用 HMAC 或 RSA 加密。
- JWT 中包含的用戶信息不應(yīng)該過多,只保留必要的信息即可。
- 在使用 JWT 進(jìn)行身份驗(yàn)證時(shí),需要防止令牌被盜用??梢圆捎靡恍┘夹g(shù)手段,比如限制令牌的有效期、限制令牌的使用次數(shù)等。
- 在生成 JWT 時(shí)需要注意加鹽加密,以提高安全性。
- 在解析 JWT 時(shí)需要對 JWT 進(jìn)行校驗(yàn),以保證 JWT 的真實(shí)性和完整性。
- 最后,需要注意遵循安全的開發(fā)實(shí)踐,保障應(yīng)用的安全性。
以上就是淺談JWT原理以及在GO中的使用方法的詳細(xì)內(nèi)容,更多關(guān)于JWT及在GO中的使用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go利用反射reflect實(shí)現(xiàn)獲取接口變量信息
反射是通過實(shí)體對象獲取反射對象(Value、Type),然后可以操作相應(yīng)的方法。本文將利用Go語言中的反射reflect實(shí)現(xiàn)獲取接口變量信息,需要的可以參考一下2022-05-05gin使用自定義結(jié)構(gòu)綁定表單數(shù)據(jù)的示例代碼
這篇文章主要介紹了gin使用自定義結(jié)構(gòu)綁定表單數(shù)據(jù)的示例代碼,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11vscode插件設(shè)置之Golang開發(fā)環(huán)境配置全過程
go語言開發(fā)選擇vscode作為IDE工具也是一個(gè)不錯(cuò)的選擇,下面這篇文章主要給大家介紹了關(guān)于vscode插件設(shè)置之Golang開發(fā)環(huán)境配置的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-12-12詳解Go語言中用 os/exec 執(zhí)行命令的五種方法
這篇文章主要介紹了Go語言中用 os/exec 執(zhí)行命令的五種方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11