Ai
76 Star 670 Fork 290

ThingsPanel/thingspanel-backend-community

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
jwt_auth.go 3.18 KB
一键复制 编辑 原始数据 按行查看 历史
路滑 提交于 2025-08-05 11:09 +08:00 . Feat: apikey增加用户支持
package middleware
import (
"context"
"net/http"
"time"
"project/internal/dal"
"project/pkg/global"
utils "project/pkg/utils"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
)
// 错误码常量
const (
ErrCodeNoAuth = 40100 // 缺少认证信息
ErrCodeInvalidToken = 40101 // 无效的Token
ErrCodeTokenExpired = 40102 // Token已过期
ErrCodeInvalidAPIKey = 40103 // 无效的APIKey
ErrCodeAPIKeyDisabled = 40104 // APIKey已禁用
)
// 统一的错误响应结构
type ErrorResponse struct {
Code int `json:"code"` // 错误码
Message string `json:"message"` // 错误描述
RequestID string `json:"request_id,omitempty"` // 请求ID,方便追踪
}
// JWTAuth 中间件,检查token和APIKey
func JWTAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// 1. 优先检查 JWT token
token := c.Request.Header.Get("x-token")
if token != "" {
if isValidJWT(c, token) {
c.Next()
return
}
// JWT验证失败,已经发送了错误响应,直接返回
return
}
// 2. 尝试 APIKey 验证
if !OpenAPIKeyAuth(c) {
// APIKey 验证也失败,在 OpenAPIKeyAuth 中已经设置了错误响应
return
}
// APIKey 验证成功
c.Next()
}
}
// isValidJWT 验证JWT token
func isValidJWT(c *gin.Context, token string) bool {
requestID := c.GetString("X-Request-ID")
// 验证 Redis 中的 token
if global.REDIS.Get(context.Background(), token).Val() != "1" {
c.JSON(http.StatusUnauthorized, ErrorResponse{
Code: ErrCodeTokenExpired,
Message: "token has expired",
RequestID: requestID,
})
c.Abort()
return false
}
// 刷新 token 过期时间
timeout := viper.GetInt("session.timeout")
logrus.Infof("刷新 token 过期时间: %d 分钟", timeout)
logrus.Infof("token: %s", token)
global.REDIS.Set(context.Background(), token, "1", time.Duration(timeout)*time.Minute)
// 验证 JWT
key := viper.GetString("jwt.key")
j := utils.NewJWT([]byte(key))
claims, err := j.ParseToken(token)
if err != nil {
c.JSON(http.StatusUnauthorized, ErrorResponse{
Code: ErrCodeInvalidToken,
Message: "invalid token format",
RequestID: requestID,
})
c.Abort()
return false
}
// 设置 claims 到上下文
c.Set("claims", claims)
return true
}
// OpenAPIKeyAuth APIKey 验证
func OpenAPIKeyAuth(c *gin.Context) bool {
requestID := c.GetString("X-Request-ID")
appKey := c.Request.Header.Get("x-api-key")
if appKey == "" {
c.JSON(http.StatusUnauthorized, ErrorResponse{
Code: ErrCodeNoAuth,
Message: "missing authentication (x-token or x-api-key required)",
RequestID: requestID,
})
c.Abort()
return false
}
tenantID, createdID, err := dal.VerifyOpenAPIKey(context.Background(), appKey)
if err != nil {
errCode := ErrCodeInvalidAPIKey
errMsg := "api key verification failed"
c.JSON(http.StatusUnauthorized, ErrorResponse{
Code: errCode,
Message: errMsg,
RequestID: requestID,
})
c.Abort()
return false
}
// 设置 claims 到上下文
claims := utils.UserClaims{
TenantID: tenantID,
Authority: "TENANT_ADMIN",
ID: createdID,
}
c.Set("claims", &claims)
return true
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/ThingsPanel/thingspanel-backend-community.git
git@gitee.com:ThingsPanel/thingspanel-backend-community.git
ThingsPanel
thingspanel-backend-community
thingspanel-backend-community
main

搜索帮助