在 Web 開發中,身份驗證是一個繞不開的話題。傳統的 Session 機制依賴服務器存儲用戶狀態,而在微服務、分布式架構下,這種方式可能會導致狀態同步困難。
JWT(JSON Web Token)是一種無狀態的、跨平臺的身份驗證解決方案,非常適合現代 Web API 場景。
本文將帶你用 Go 實現一個?JWT 登錄驗證示例,掌握它的基本原理與使用方式。
一、什么是 JWT
JWT 的結構由三部分組成:
header.payload.signature
- ??Header:聲明類型(JWT)和加密算法(如 HMAC SHA256)。
- ??Payload:存放業務數據(如用戶ID、角色、過期時間)。
- ??Signature:對前兩部分進行簽名,保證數據不可篡改。
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJ1c2VyX2lkIjoxLCJleHAiOjE3MDAwMDAwMDB9
.abc123456789xyz
二、實現思路
- 1.?用戶登錄?→ 校驗賬號密碼正確 → 生成 JWT 返回給前端。
- 2.?前端請求 API?→ 在?
Authorization
?頭中攜帶 JWT。 - 3.?后端中間件?→ 解析 JWT,驗證有效性與過期時間。
- 4.?通過驗證?→ 執行后續業務邏輯。
三、代碼實現
我們使用?github.com/golang-jwt/jwt/v5
?作為 JWT 庫。
1. 初始化依賴
go?get?github.com/golang-jwt/jwt/v5
2. 定義 JWT 工具
package?mainimport?("fmt""time""github.com/golang-jwt/jwt/v5"
)var?jwtSecret?=?[]byte("my_secret_key")//?生成Token
func?GenerateToken(username?string)?(string,?error)?{claims?:=?jwt.MapClaims{"username":?username,"exp":??????time.Now().Add(2?*?time.Hour).Unix(),"iat":??????time.Now().Unix(),}token?:=?jwt.NewWithClaims(jwt.SigningMethodHS256,?claims)return?token.SignedString(jwtSecret)
}//?驗證Token
func?ParseToken(tokenString?string)?(jwt.MapClaims,?error)?{token,?err?:=?jwt.Parse(tokenString,?func(token?*jwt.Token)?(interface{},?error)?{return?jwtSecret,?nil})if?claims,?ok?:=?token.Claims.(jwt.MapClaims);?ok?&&?token.Valid?{return?claims,?nil}return?nil,?err
}
3. 構建簡單登錄和受保護接口
package?mainimport?("encoding/json""fmt""net/http""strings"
)//?模擬用戶數據
var?users?=?map[string]string{"alice":?"123456","bob":???"654321",
}func?loginHandler(w?http.ResponseWriter,?r?*http.Request)?{username?:=?r.FormValue("username")password?:=?r.FormValue("password")if?pwd,?ok?:=?users[username];?!ok?||?pwd?!=?password?{http.Error(w,?"用戶名或密碼錯誤",?http.StatusUnauthorized)return}token,?_?:=?GenerateToken(username)w.Header().Set("Content-Type",?"application/json")json.NewEncoder(w).Encode(map[string]string{"token":?token})
}func?authMiddleware(next?http.HandlerFunc)?http.HandlerFunc?{return?func(w?http.ResponseWriter,?r?*http.Request)?{authHeader?:=?r.Header.Get("Authorization")if?authHeader?==?""?{http.Error(w,?"缺少Authorization頭",?http.StatusUnauthorized)return}parts?:=?strings.SplitN(authHeader,?"?",?2)if?len(parts)?!=?2?||?parts[0]?!=?"Bearer"?{http.Error(w,?"Authorization格式錯誤",?http.StatusUnauthorized)return}claims,?err?:=?ParseToken(parts[1])if?err?!=?nil?{http.Error(w,?"無效Token",?http.StatusUnauthorized)return}fmt.Printf("JWT解析結果:?%+v\n",?claims)next.ServeHTTP(w,?r)}
}func?protectedHandler(w?http.ResponseWriter,?r?*http.Request)?{fmt.Fprintln(w,?"歡迎訪問受保護的資源!")
}func?main()?{http.HandleFunc("/login",?loginHandler)http.HandleFunc("/protected",?authMiddleware(protectedHandler))fmt.Println("服務器啟動:http://localhost:8080")http.ListenAndServe(":8080",?nil)
}
4. 測試流程
- 1.?登錄獲取 Token
curl?-X?POST?"http://localhost:8080/login"?-d?"username=alice&password=123456"
返回:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI..."}
- 2.?訪問受保護接口
curl?-H?"Authorization:?Bearer?eyJhbGciOiJIUzI1NiIsInR5cCI..."?http://localhost:8080/protected
輸出:
歡迎訪問受保護的資源!
四、注意事項
- 1.?Token 過期處理:前端需在過期后重新獲取 Token。
- 2.?Secret 安全性:切勿將?
jwtSecret
?寫死在代碼里,可用環境變量管理。 - 3.?HTTPS:避免 Token 在明文傳輸中被竊取。
- 4.?黑名單機制:如果需要即時讓某個 Token 失效,可以維護一個黑名單。
五、總結
JWT 在 Go 中實現并不復雜,但它帶來的無狀態身份驗證機制,非常適合 RESTful API 和分布式架構場景。
通過本示例,你可以快速搭建一個基于 JWT 的登錄驗證系統,并根據業務需求進行擴展,比如刷新 Token、角色權限控制等。