JWT认证 #
一、JWT概述 #
1.1 什么是JWT #
JWT(JSON Web Token)是一种开放标准,用于在各方之间安全传输信息。
1.2 JWT结构 #
text
Header.Payload.Signature
示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxfQ.abc123
二、安装依赖 #
bash
go get github.com/golang-jwt/jwt/v4
三、Token生成 #
3.1 基本生成 #
go
package main
import (
"time"
"github.com/golang-jwt/jwt/v4"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
UserID string `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func GenerateToken(userID, role string) (string, error) {
claims := Claims{
UserID: userID,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
Issuer: "my-app",
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
3.2 登录接口 #
go
app.Post("/login", func(c *fiber.Ctx) error {
type LoginInput struct {
Username string `json:"username"`
Password string `json:"password"`
}
var input LoginInput
if err := c.BodyParser(&input); err != nil {
return c.Status(400).JSON(fiber.Map{
"error": "Invalid input",
})
}
// 验证用户(示例)
if input.Username != "admin" || input.Password != "password" {
return c.Status(401).JSON(fiber.Map{
"error": "Invalid credentials",
})
}
// 生成Token
token, err := GenerateToken("1", "admin")
if err != nil {
return c.Status(500).JSON(fiber.Map{
"error": "Failed to generate token",
})
}
return c.JSON(fiber.Map{
"token": token,
})
})
四、Token验证 #
4.1 验证中间件 #
go
func JWTMiddleware() fiber.Handler {
return func(c *fiber.Ctx) error {
authHeader := c.Get("Authorization")
if authHeader == "" {
return c.Status(401).JSON(fiber.Map{
"error": "Missing authorization header",
})
}
// 解析Bearer Token
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
return c.Status(401).JSON(fiber.Map{
"error": "Invalid authorization format",
})
}
tokenString := parts[1]
// 解析Token
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil || !token.Valid {
return c.Status(401).JSON(fiber.Map{
"error": "Invalid token",
})
}
// 获取Claims
claims, ok := token.Claims.(*Claims)
if !ok {
return c.Status(401).JSON(fiber.Map{
"error": "Invalid claims",
})
}
// 存储用户信息
c.Locals("user_id", claims.UserID)
c.Locals("role", claims.Role)
return c.Next()
}
}
4.2 使用中间件 #
go
protected := app.Group("/api", JWTMiddleware())
protected.Get("/profile", func(c *fiber.Ctx) error {
userID := c.Locals("user_id").(string)
role := c.Locals("role").(string)
return c.JSON(fiber.Map{
"user_id": userID,
"role": role,
})
})
五、Token刷新 #
5.1 刷新Token #
go
app.Post("/refresh", JWTMiddleware(), func(c *fiber.Ctx) error {
userID := c.Locals("user_id").(string)
role := c.Locals("role").(string)
// 生成新Token
newToken, err := GenerateToken(userID, role)
if err != nil {
return c.Status(500).JSON(fiber.Map{
"error": "Failed to refresh token",
})
}
return c.JSON(fiber.Map{
"token": newToken,
})
})
六、完整示例 #
go
package main
import (
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v4"
)
var jwtSecret = []byte("your-secret-key")
type Claims struct {
UserID string `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func GenerateToken(userID, role string) (string, error) {
claims := Claims{
UserID: userID,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(jwtSecret)
}
func JWTMiddleware() fiber.Handler {
return func(c *fiber.Ctx) error {
authHeader := c.Get("Authorization")
if authHeader == "" {
return c.Status(401).JSON(fiber.Map{"error": "Unauthorized"})
}
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
return c.Status(401).JSON(fiber.Map{"error": "Invalid format"})
}
token, err := jwt.ParseWithClaims(parts[1], &Claims{}, func(t *jwt.Token) (interface{}, error) {
return jwtSecret, nil
})
if err != nil || !token.Valid {
return c.Status(401).JSON(fiber.Map{"error": "Invalid token"})
}
claims := token.Claims.(*Claims)
c.Locals("user_id", claims.UserID)
c.Locals("role", claims.Role)
return c.Next()
}
}
func main() {
app := fiber.New()
app.Post("/login", func(c *fiber.Ctx) error {
var input struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.BodyParser(&input); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid input"})
}
if input.Username != "admin" || input.Password != "password" {
return c.Status(401).JSON(fiber.Map{"error": "Invalid credentials"})
}
token, _ := GenerateToken("1", "admin")
return c.JSON(fiber.Map{"token": token})
})
protected := app.Group("/api", JWTMiddleware())
protected.Get("/profile", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{
"user_id": c.Locals("user_id"),
"role": c.Locals("role"),
})
})
app.Listen(":3000")
}
七、总结 #
7.1 JWT认证流程 #
text
1. 用户登录 → 验证凭据
2. 生成Token → 返回给客户端
3. 客户端存储Token
4. 请求携带Token → 验证Token
5. 返回受保护资源
7.2 下一步 #
现在你已经掌握了JWT认证,接下来让我们学习 CORS跨域,了解跨域处理!
最后更新:2026-03-28