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