当前位置: 首页 > article >正文

Gin从入门到精通(八)身份验证与授权(JWT)

身份验证与授权(JWT)

Gin 支持通过 JWT(JSON Web Token)来实现用户的身份验证。通过中间件验证用户的身份后,可以控制资源的访问权限。

JWT 认证流程 :

1. 用户登录 → 服务端验证 → 生成 JWT → 返回 Token  
2. 客户端存储 Token → 后续请求携带 Token  
3. 服务端验证 Token → 允许/拒绝访问  

1.代码实现

1.1使用jwt库

安装jwt-go库:

go get  github.com/dgrijalva/jwt-go

1.2 项目结构

创建如下的项目结构:

.
├── main.go
├── models/
│   └── user.go
├── handlers/
│   ├── auth.go
│   └── user.go
└── middleware/
    └── jwt.go

1.3定义用户模型与密钥

修改models/user.go文件:

// models/user.go
type User struct {
    ID       uint   `json:"id"`
    Username string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required"`
}

// 示例用户数据(实际应从数据库读取)
var Users = []User{
    {ID: 1, Username: "admin", Password: "admin123"},
}

// 定义 JWT 密钥(需保密,生产环境应从配置读取)
var JwtSecret = []byte("your-secret-key") // 值需要8位以上

1.4 用户登录与生成 JWT

修改 handlers/auth.go 文件:

// handlers/auth.go
package handlers

import (
    "net/http"
    "time"
    "github.com/gin-gonic/gin"
	"github.com/dgrijalva/jwt-go"
    "JwtDemo/models"
)

type LoginRequest struct {
    Username string `json:"username" binding:"required"`
    Password string `json:"password" binding:"required"`
}

func Login(c *gin.Context) {
    var req LoginRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"})
        return
    }

    // 校验用户(示例代码,实际应查询数据库)
    var user *models.User
    for _, u := range models.Users {
        if u.Username == req.Username && u.Password == req.Password {
            user = &u
            break
        }
    }
    if user == nil {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
        return
    }

    // 生成 JWT
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "user_id":  user.ID,
        "username": user.Username,
        "exp":      time.Now().Add(time.Hour * 24).Unix(), // 过期时间 24 小时
    })

    tokenString, err := token.SignedString(models.JwtSecret)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "生成 Token 失败"})
        return
    }

    c.JSON(http.StatusOK, gin.H{"token": tokenString})
}

1.5编写 JWT 验证中间件

修改middleware/jwt.go 文件:

// middleware/jwt.go
package middleware

import (
    "net/http"
    "strings"
  	"github.com/dgrijalva/jwt-go"
    "JwtDemo/models"
)

func JWTAuth() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 从 Header 中获取 Token
        authHeader := c.GetHeader("Authorization")
        if authHeader == "" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "未提供 Token"})
            return
        }

        // 提取 Token(格式:Bearer <token>)
        parts := strings.Split(authHeader, " ")
        if len(parts) != 2 || parts[0] != "Bearer" {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Token 格式错误"})
            return
        }
        tokenString := parts[1]

        // 解析并验证 Token
        token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
            if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, jwt.ErrSignatureInvalid
            }
            return models.JwtSecret, nil
        })

        if err != nil || !token.Valid {
            c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "无效的 Token"})
            return
        }

        // 将 Claims 存入上下文
        if claims, ok := token.Claims.(jwt.MapClaims); ok {
            c.Set("user_id", claims["user_id"])
            c.Set("username", claims["username"])
        }

        c.Next()
    }
}

1.6注册路由与使用中间件

修改main.go文件:

// main.go
package main

import (
    "JwtDemo/handlers"
    "JwtDemo/middleware"
    "github.com/gin-gonic/gin"
)

func main() {
    r := gin.Default()

    // 公开路由:登录
    r.POST("/login", handlers.Login)

    // 受保护路由组
    protected := r.Group("/api")
    protected.Use(middleware.JWTAuth())
    {
        protected.GET("/profile", func(c *gin.Context) {
            userID, _ := c.Get("user_id")
            username, _ := c.Get("username")
            c.JSON(200, gin.H{
                "user_id":  userID,
                "username": username,
            })
        })
    }

    r.Run(":8080")
}

2.测试接口

2.1模拟登录获取Token

访问地址:

http://localhost:8080/login

请求参数:

{
    "username" :"admin",
    "password" :"admin123"
}

返回参数:

{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDAzMTkyNTIsInVzZXJfaWQiOjEsInVzZXJuYW1lIjoiYWRtaW4ifQ.k8TKg4-hZj5XTi7e6A9riXTA-jmf3K3SwXrdwZnqCf4"}

在这里插入图片描述

2.2 使用token访问保护路由

访问地址:

http://localhost:8080/api/profile

添加请求头:

Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDAzMTkyNTIsInVzZXJfaWQiOjEsInVzZXJuYW1lIjoiYWRtaW4ifQ.k8TKg4-hZj5XTi7e6A9riXTA-jmf3K3SwXrdwZnqCf4

注意:jwt的传递是在HTTP请求添加名为Authorization的header,形式如下 Authorization: Bearer <token> ,注意 Bearer <token> 之间有空格

返回参数:

{
    "user_id": 1,
    "username": "admin"
}

在这里插入图片描述

3.使用BasicAuth中间件

BasicAuth 是 Gin 框架内置的中间件,用于实现 HTTP 基本认证(Basic Authentication)。它通过用户名和密码保护指定的路由,适用于简单的权限控制场景(如管理后台、内部工具等)。

演示代码:

package main

import (
	"encoding/base64"
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	router := gin.Default()

	// 定义合法账户
	//	gin.Accounts 是 map[string]string 的一种快捷方式
	accounts := gin.Accounts{
		"admin": "admin123",
		"user":  "user123",
	}

	// 创建 BasicAuth 中间件
	auth := gin.BasicAuth(accounts)

	// 受保护的路由组
	admin := router.Group("/admin", auth)
	{
		admin.GET("/secrets", func(c *gin.Context) {
			// 获取用户,它是由 BasicAuth 中间件设置的
			user := c.MustGet(gin.AuthUserKey).(string)
			//fmt.Println(c.MustGet("Authorization").(string))
			if secret, ok := accounts[user]; ok {
				c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret, "auth": base64.StdEncoding.EncodeToString([]byte(user + ":" + accounts[user]))})
			} else {
				c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
			}
		})
	}

	// 公开路由
	router.GET("/", func(c *gin.Context) {
		c.String(200, "首页(无需认证)")
	})

	router.Run(":8080")
}


测试请求:

curl -u admin:admin123 http://localhost:8080/admin/secrets

客户端需在请求头中携带 Authorization 字段,格式为 Basic base64(username:password)
例如,用户 admin 密码 admin123 的认证头为:

Authorization: Basic YWRtaW46YWRtaW4xMjM=

使用 Authorization 来测试
在这里插入图片描述


http://www.kler.cn/a/560099.html

相关文章:

  • 【C语言基础】基本数据类型和常量介绍
  • 2025 银行业科技金融创新与发展报告
  • 如何查看图片的原始格式
  • c高级终端指令
  • 【R语言】dplyr包经典函数summarise函数
  • 测试面试题:以一个登录窗口为例,设计一下登录界面测试的思路和方法
  • 【JavaEE】SpringMVC 请求传参
  • Ubuntu非conda环境python3.8下安装labelme
  • Vue全局变量的定义和使用,创建 Store变量、读取、修改
  • Django数据库操作
  • 最长递增子序列(贪心算法)思路+源码
  • zookeeper从入门到精通
  • 在CentOS7上部署与关闭Flask接口
  • GoFly框架中集成Bolt 和badfer两个Go语言嵌入式键值数据库
  • 2025.2.24总结
  • 【java】重载(overloading)和重写(overriding)
  • 单片机分层架构的头文件设计
  • springboot集成jackson-dataformat-xml实现发送XML请求和XML响应参数处理
  • 商业银行预算管理系统的架构、流程、原型
  • 一周学会Flask3 Python Web开发-flask3上下文全局变量session,g和current_app