go开发gin web中的用户验证怎么实现?
在 Gin Web 应用中实现用户验证,常见的方式有基于令牌(Token)的验证和基于 Session - Cookie 的验证。以下分别介绍这两种方式的实现思路和代码示例:
基于令牌(Token)的验证
- 生成和验证 Token:通常使用 JWT(JSON Web Token)。JWT 由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
- 中间件验证:在 Gin 中通过中间件来验证请求中的 Token 是否有效。
示例代码
package main
import (
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"net/http"
"time"
)
// 定义 JWT 密钥
const jwtSecret = "your-secret-key"
// Claims 自定义载荷结构
type Claims struct {
UserID uint `json:"user_id"`
jwt.StandardClaims
}
// GenerateToken 生成 JWT
func GenerateToken(userID uint) (string, error) {
expirationTime := time.Now().Add(5 * time.Minute)
claims := &Claims{
UserID: userID,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(jwtSecret))
}
// VerifyToken 验证 JWT
func VerifyToken(tokenString string) (*Claims, bool) {
claims := &Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
return []byte(jwtSecret), nil
})
if err != nil ||!token.Valid {
return nil, false
}
return claims, true
}
// AuthMiddleware 验证中间件
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "未提供认证令牌"})
c.Abort()
return
}
tokenString = tokenString[len("Bearer "):]
claims, ok := VerifyToken(tokenString)
if!ok {
c.JSON(http.StatusUnauthorized, gin.H{"error": "无效的认证令牌"})
c.Abort()
return
}
c.Set("user_id", claims.UserID)
c.Next()
}
}
func main() {
r := gin.Default()
r.POST("/login", func(c *gin.Context) {
// 模拟登录验证
var login struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求格式错误"})
return
}
if login.Username == "admin" && login.Password == "password" {
token, err := GenerateToken(1)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "生成令牌失败"})
return
}
c.JSON(http.StatusOK, gin.H{"token": token})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
}
})
r.GET("/protected", AuthMiddleware(), func(c *gin.Context) {
userID := c.MustGet("user_id").(uint)
c.JSON(http.StatusOK, gin.H{"message": "这是受保护的路由", "user_id": userID})
})
r.Run(":8080")
}
基于 Session - Cookie 的验证
- 初始化 Session:使用
github.com/gorilla/sessions库来管理会话。 - 登录时设置 Session:验证用户登录信息后,在 Session 中记录用户状态。
- 中间件验证 Session:通过中间件检查 Session 中用户是否已登录。
示例代码
package main
import (
"github.com/gin-gonic/gin"
"github.com/gorilla/sessions"
"net/http"
)
// 定义 Session 存储
var store = sessions.NewCookieStore([]byte("your-secret-key"))
// Login 处理登录请求
func Login(c *gin.Context) {
var login struct {
Username string `json:"username"`
Password string `json:"password"`
}
if err := c.ShouldBindJSON(&login); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求格式错误"})
return
}
if login.Username == "admin" && login.Password == "password" {
session, _ := store.Get(c.Request, "user-session")
session.Values["is_logged_in"] = true
session.Values["user_id"] = 1
session.Save(c.Request, c.ResponseWriter)
c.JSON(http.StatusOK, gin.H{"message": "登录成功"})
} else {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
}
}
// AuthMiddleware 验证 Session 中间件
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
session, err := store.Get(c.Request, "user-session")
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"})
c.Abort()
return
}
isLoggedIn := session.Values["is_logged_in"]
if isLoggedIn != true {
c.JSON(http.StatusUnauthorized, gin.H{"error": "未登录"})
c.Abort()
return
}
c.Next()
}
}
func main() {
r := gin.Default()
r.POST("/login", Login)
r.GET("/protected", AuthMiddleware(), func(c *gin.Context) {
session, _ := store.Get(c.Request, "user-session")
userID := session.Values["user_id"]
c.JSON(http.StatusOK, gin.H{"message": "这是受保护的路由", "user_id": userID})
})
r.Run(":8080")
}
以上两种方式各有优缺点,基于 Token 的方式适合无状态的分布式架构,而基于 Session - Cookie 的方式更适合传统的 Web 应用场景。你可以根据项目的具体需求来选择合适的方式。
本文来自博客园,作者:gosamuel,转载请注明原文链接:https://www.cnblogs.com/woloveai/p/19038285

浙公网安备 33010602011771号