什么JWT
JWT(JSON Web Token)是一種開放標準(RFC 7519),定義了一種在各方之間安全傳輸信息的簡潔方式。這些信息可以被驗證和信任,因為它們是數字簽名的。
JWT由三部分組成,用.
分隔。它們分別是Header(頭部)、Payload(負載)和Signature(簽名)。
-
Header:通常由兩部分組成:token類型和使用的加密算法。
-
Payload:存放有效信息的地方。有效信息包括三個部分:聲明類型、公共聲明和私有聲明。
-
Signature:簽名是由頭部、負載、密鑰和加密算法組合而來,用于驗證消息沒有被篡改。
在網絡應用中,JWT通常用于鑒權。服務器生成一個token返回給客戶端,客戶端以后的每次請求都會帶上這個token,服務器通過這個token識別和驗證客戶端的身份。由于JWT內部包含了識別客戶端的信息,并且被加密,所以是安全的。同時,JWT也是無狀態的,服務器不需要存儲任何客戶端的信息,這對于分布式應用來說是一個很大的優勢。
優點:
-
簡潔:JWT是為了在網絡應用環境間傳遞聲明而執行的。因為是輕量化的,所以它可用于SSO(Single Sign On單點登錄)。
-
安全:JWT的ClAIms(聲明)是被加密的,采用的是一個密鑰,只有簽發者才能使用那個密鑰,這保證了安全。
-
方便:無狀態,不需要在服務器存儲用戶狀態,這使得應用更容易擴展。
缺點:
-
體積較大:因為JWT需要在每次請求頭上帶上token,如果token過大可能會導致請求頭過大,不如sessionID方式中uuid那么輕便。
-
存儲敏感信息:雖然JWT的Payload(負載)部分采取了Base64Url 編碼進行轉義,但這僅僅是編碼而已,并非加密操作,需要避免在聲明中放入敏感信息。
-
無自動過期機制:JWT一旦簽發在到期時間之前會一直有效,不像session那樣在用戶登出之后可以直接銷毀。這就需要服務器提供黑名單機制來強制讓token失效。
總的來說,在很多場合,尤其是分布式無狀態應用,JWT是一個很好的選擇,能夠提供便捷的權限管理功能。但同時也要注意其潛在的安全問題,尤其是避免將敏感信息放在payload中,并提供充分的安全防護,例如采用HTTPS、定期更換秘鑰、提供token黑名單機制等。不過雖然JWT的缺點不能直接銷毀,但是可以通過在服務端存儲key的形式,通過每次獲取請求頭然后比對緩存中的值一旦緩存值過期則表示失效可以間接避免缺點3.
Go中如何使用JWT
-
安裝jwt-go庫:在Go語中,有一個非常優秀的處理
JWT
的庫jwt-go
,可以直接使用go get
命令進行安裝: -
go get Github.com/dgrijalva/jwt-go
3.我們需要定義一個結構體,表示我們自定義的 Claims。這個結構體需要嵌入 jwt.StandardClaims
,然后添加我們需要的字段,比如 UserID:
func main() {
v1, err := CreateTokenV1("456", false)
fmt.Printf(v1,err)
ParseTokenV2(v1,"456")
}
func CreateTokenV1(secretKey string, isNotExpired bool) (string, error){
var expirationTime = time.Now().Add(24 * time.Hour)
if isNotExpired {
expirationTime = time.Now().Add(40 * 24 * time.Hour)
}
claims := &MyCustomClaims{
jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(),
},
123,//用戶id
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secretKey))
}
func ParseTokenV2(tokenString string, secretKey string){
token, _ := jwt.ParseWithClaims(tokenString, &MyCustomClaims{}, func(t *jwt.Token) (interface{}, error) {
return []byte(secretKey), nil
})
if claims, ok := token.Claims.(*MyCustomClaims); ok && token.Valid {
fmt.Println(claims.UserID)
}
}
type MyCustomClaims struct {
jwt.StandardClaims
UserID int `json:"user_id"`
}
-
接著,在生成 token 時,我們需要創建一個 MyCustomClaims 的實例,設置 UserID,且此時可以設置 token 的有效期(ExpireAt)等其他標準字段:
-
最后,在解析 token 時,我們需要解析到我們的自定義 Claims 結構體中,這樣就可以獲取用戶 ID 了:
-
CreateTokenV1和ParseTokenV2分別代表著創建和解析
-
以上只是一種最基本的實現方式,在實際應用場景中,一般會在
claims
中包含更多信息,比如用戶ID、用戶名等。同時也需要對錯誤情況進行更多處理