golang,go,博客,开源,编程
在 Go 语言中实现 JWT 认证非常简单,通常使用第三方库来简化签名、验证等操作。最常用的库是 github.com/dgrijalva/jwt-go
(或其继任者 github.com/golang-jwt/jwt
)。以下是如何在 Go 中实现一个完整的 JWT 认证流程的详细步骤。
首先,确保安装了必要的依赖:
go get github.com/golang-jwt/jwt/v4
生成 JWT 需要使用 jwt-go
库来创建一个新的令牌。在生成过程中,我们会创建一个包含用户信息的负载,并使用密钥对其进行签名。
package main
import (
"fmt"
"time"
"log"
"github.com/golang-jwt/jwt/v4"
)
var secretKey = []byte("your-256-bit-secret")
// 定义自定义声明
type CustomClaims struct {
Username string `json:"username"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func generateJWT(username, role string) (string, error) {
// 设置负载数据
claims := CustomClaims{
Username: username,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "myapp",
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)), // 设置过期时间为24小时
IssuedAt: jwt.NewNumericDate(time.Now()), // 设置当前时间
},
}
// 创建一个新的token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 使用secretKey对token进行签名
signedToken, err := token.SignedString(secretKey)
if err != nil {
return "", err
}
return signedToken, nil
}
func main() {
token, err := generateJWT("john_doe", "admin")
if err != nil {
log.Fatal(err)
}
fmt.Println("Generated JWT:", token)
}
Username
和 Role
,以及 JWT 的标准声明(RegisteredClaims
)。jwt.NewWithClaims
:这个方法用来生成一个新的JWT,SigningMethodHS256
是使用的签名算法(HMAC-SHA256)。SignedString(secretKey)
:使用我们定义的 secretKey
对生成的 JWT 进行签名。为了验证 JWT 的合法性,我们需要解析 JWT 并验证其签名。此过程会验证令牌的有效性,包括签名、过期时间等。
package main
import (
"fmt"
"log"
"github.com/golang-jwt/jwt/v4"
)
func parseJWT(tokenString string) (*CustomClaims, error) {
// 解析token时,提供一个回调函数来验证token的签名
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// 这里我们验证token的签名算法
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method %v", token.Header["alg"])
}
// 返回密钥
return secretKey, nil
})
if err != nil {
return nil, err
}
// 如果token合法,返回包含数据的claims
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("invalid token")
}
func main() {
// 假设我们从前端接收到的JWT
tokenString := "your-jwt-token-here"
claims, err := parseJWT(tokenString)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Token is valid!\nUsername: %s\nRole: %s\n", claims.Username, claims.Role)
}
&CustomClaims{}
表示将 JWT 的负载映射到我们的自定义声明结构体 CustomClaims
。func(token *jwt.Token)
用来返回验证 JWT 的密钥。你可以在 Web 应用中使用 JWT 来实现用户认证流程。假设我们有一个登录端点来生成 JWT,并且需要保护一些需要认证的资源(如用户信息)。
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/golang-jwt/jwt/v4"
)
var secretKey = []byte("your-256-bit-secret")
type CustomClaims struct {
Username string `json:"username"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func generateJWT(username, role string) (string, error) {
claims := CustomClaims{
Username: username,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
Issuer: "myapp",
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
signedToken, err := token.SignedString(secretKey)
if err != nil {
return "", err
}
return signedToken, nil
}
func parseJWT(tokenString string) (*CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method %v", token.Header["alg"])
}
return secretKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, fmt.Errorf("invalid token")
}
// 登录端点,返回JWT
func login(w http.ResponseWriter, r *http.Request) {
username := r.URL.Query().Get("username")
role := r.URL.Query().Get("role")
token, err := generateJWT(username, role)
if err != nil {
http.Error(w, "Could not generate token", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"token": "%s"}`, token)
}
// 受保护资源端点
func protected(w http.ResponseWriter, r *http.Request) {
tokenString := r.Header.Get("Authorization")
if tokenString == "" {
http.Error(w, "Authorization header missing", http.StatusUnauthorized)
return
}
claims, err := parseJWT(tokenString)
if err != nil {
http.Error(w, "Invalid token", http.StatusUnauthorized)
return
}
w.Header().Set("Content-Type", "application/json")
fmt.Fprintf(w, `{"message": "Welcome %s!", "role": "%s"}`, claims.Username, claims.Role)
}
func main() {
http.HandleFunc("/login", login)
http.HandleFunc("/protected", protected)
log.Fatal(http.ListenAndServe(":8080", nil))
}
/login
:模拟一个用户登录过程,返回一个 JWT 令牌。/protected
:一个受保护的端点,只有提供有效 JWT 的用户才能访问。http://localhost:8080/login?username=john_doe&role=admin
生成 JWT。Authorization
头部,访问 http://localhost:8080/protected
,可以看到受保护的资源内容。github.com/golang-jwt/jwt
库。jwt.NewWithClaims
来创建 JWT,并使用密钥进行签名。jwt.ParseWithClaims
来验证 JWT 的签名并提取负载信息。