feat: build core architecture & implement user auth modules 🚀 feat: 搭建核心架构并实现用户认证模块 🚀 Framework Migration: Switched from Hertz to Gin, providing a more idiomatic and lightweight web foundation. ⚡ 框架迁移:从 Hertz 切换至 Gin,构建了更符合 Go 惯例且轻量级的 Web 基础。⚡ Architectural Overhaul: Refactored the 3-layer architecture from global-variable-based calls to Explicit Dependency Injection (DI) via New... factory functions. This significantly improves testability and decoupling. 🏗️ 架构重构:将三层架构从基于“全局变量”的调用重构为通过 New... 工厂函数实现的显式依赖注入 (DI)。这大幅提升了代码的可测试性与解耦程度。🏗️ User Auth: Completed and tested Register, Login, and Token Refresh APIs with robust error handling and Bcrypt password hashing. 🔐 用户认证:完成了注册、登录与 Token 刷新接口并通过测试,包含健壮的错误处理与 Bcrypt 密码哈希加密。🔐 Config Management: Integrated Viper for centralized, environment-aware configuration management. ⚙️ 配置管理:集成了 Viper,实现了中心化且具备环境感知能力的配置管理。⚙️ DevOps & Docs: Added docker-compose.yml for seamless MySQL 8.0 & environment setup. 🐳 Updated README.md with corrections for mistakes in image quoting and formats. 📝 运维与文档: 新增 docker-compose.yml,实现 MySQL 8.0 环境的一键启动。🐳 更新 README.md,修改了一些图片引用和格式上小错误。📝
69 lines
2.2 KiB
Go
69 lines
2.2 KiB
Go
package auth
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/golang-jwt/jwt/v4"
|
|
"github.com/smartflow/backend/respond"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
var RefreshKey = []byte(viper.GetString("jwt.accessSecret")) // 用于签名和验证刷新Token的密钥
|
|
var AccessKey = []byte(viper.GetString("jwt.refreshSecret")) // 用于签名和验证访问Token的密钥
|
|
|
|
// GenerateTokens 生成访问令牌和刷新令牌
|
|
func GenerateTokens(userID int) (string, string, error) {
|
|
// 创建访问令牌
|
|
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
"user_id": userID, // 获取用户ID
|
|
"exp": time.Now().Add(15 * time.Minute).Unix(), // 设置访问令牌过期时间为 15 分钟
|
|
"token_type": "access_token", // 令牌类型为访问令牌
|
|
})
|
|
|
|
// 使用密钥签名访问令牌
|
|
accessTokenString, err := accessToken.SignedString(AccessKey)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
// 创建刷新令牌
|
|
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
|
"user_id": userID, // 获取用户ID
|
|
"exp": time.Now().Add(7 * 24 * time.Hour).Unix(), // 设置刷新令牌过期时间为 7 天
|
|
"token_type": "refresh_token", // 令牌类型为刷新令牌
|
|
})
|
|
|
|
// 使用密钥签名刷新令牌
|
|
refreshTokenString, err := refreshToken.SignedString(RefreshKey)
|
|
if err != nil {
|
|
return "", "", err
|
|
}
|
|
|
|
return accessTokenString, refreshTokenString, nil
|
|
}
|
|
|
|
func ValidateRefreshToken(tokenString string) (*jwt.Token, error) {
|
|
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
|
|
// 检查签名方法是否为 HMAC
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, respond.InvalidTokenSingingMethod
|
|
}
|
|
// 返回用于验证的密钥
|
|
return RefreshKey, nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 进一步检查载荷中 token_type 是否正确
|
|
claims, ok := token.Claims.(jwt.MapClaims)
|
|
if !ok {
|
|
return nil, respond.InvalidClaims
|
|
}
|
|
// 检查 token_type 是否是 refresh_token
|
|
if claimType, ok := claims["token_type"].(string); !ok || claimType != "refresh_token" {
|
|
return nil, respond.WrongTokenType
|
|
}
|
|
return token, nil
|
|
}
|