做完了一部分,备份一下,防止以外删除
This commit is contained in:
53
internal/middleware/auth.go
Normal file
53
internal/middleware/auth.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/keyauth"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/validator"
|
||||
)
|
||||
|
||||
// KeyAuth 创建基于 Redis 的令牌认证中间件
|
||||
func KeyAuth(v *validator.TokenValidator, logger *zap.Logger) fiber.Handler {
|
||||
return keyauth.New(keyauth.Config{
|
||||
KeyLookup: "header:token",
|
||||
Validator: func(c *fiber.Ctx, key string) (bool, error) {
|
||||
// 验证令牌
|
||||
userID, err := v.Validate(key)
|
||||
if err != nil {
|
||||
// 获取请求 ID 用于日志
|
||||
requestID := ""
|
||||
if rid := c.Locals(constants.ContextKeyRequestID); rid != nil {
|
||||
requestID = rid.(string)
|
||||
}
|
||||
|
||||
logger.Warn("令牌验证失败",
|
||||
zap.String("request_id", requestID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// 在上下文中存储用户 ID
|
||||
c.Locals(constants.ContextKeyUserID, userID)
|
||||
return true, nil
|
||||
},
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
// 将错误映射到统一响应格式
|
||||
switch err {
|
||||
case keyauth.ErrMissingOrMalformedAPIKey:
|
||||
return response.Error(c, 400, errors.CodeMissingToken, errors.GetMessage(errors.CodeMissingToken, "zh"))
|
||||
case errors.ErrInvalidToken:
|
||||
return response.Error(c, 400, errors.CodeInvalidToken, errors.GetMessage(errors.CodeInvalidToken, "zh"))
|
||||
case errors.ErrRedisUnavailable:
|
||||
return response.Error(c, 503, errors.CodeAuthServiceUnavailable, errors.GetMessage(errors.CodeAuthServiceUnavailable, "zh"))
|
||||
default:
|
||||
return response.Error(c, 500, errors.CodeInternalError, errors.GetMessage(errors.CodeInternalError, "zh"))
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
41
internal/middleware/ratelimit.go
Normal file
41
internal/middleware/ratelimit.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/limiter"
|
||||
"github.com/gofiber/storage/redis/v3"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
)
|
||||
|
||||
// RateLimiter 创建基于 IP 的限流中间件
|
||||
// storage 参数:nil = 内存存储,传入 Redis storage = 分布式限流
|
||||
func RateLimiter(max int, expiration time.Duration, storage fiber.Storage) fiber.Handler {
|
||||
return limiter.New(limiter.Config{
|
||||
Max: max,
|
||||
Expiration: expiration,
|
||||
KeyGenerator: func(c *fiber.Ctx) string {
|
||||
// 使用统一的 Redis 键生成函数
|
||||
return constants.RedisRateLimitKey(c.IP())
|
||||
},
|
||||
LimitReached: func(c *fiber.Ctx) error {
|
||||
return response.Error(c, 400, errors.CodeTooManyRequests, errors.GetMessage(errors.CodeTooManyRequests, "zh"))
|
||||
},
|
||||
Storage: storage, // 支持内存或 Redis 存储
|
||||
})
|
||||
}
|
||||
|
||||
// NewRedisStorage 创建 Redis 存储用于限流
|
||||
func NewRedisStorage(addr, password string, db, prot int) fiber.Storage {
|
||||
return redis.New(redis.Config{
|
||||
Host: addr,
|
||||
Port: prot,
|
||||
Password: password,
|
||||
Database: db,
|
||||
Reset: false,
|
||||
})
|
||||
}
|
||||
44
internal/middleware/recover.go
Normal file
44
internal/middleware/recover.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
)
|
||||
|
||||
// Recover 创建自定义 panic 恢复中间件
|
||||
func Recover(logger *zap.Logger) fiber.Handler {
|
||||
return func(c *fiber.Ctx) error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// 获取请求 ID
|
||||
requestID := ""
|
||||
if rid := c.Locals(constants.ContextKeyRequestID); rid != nil {
|
||||
requestID = rid.(string)
|
||||
}
|
||||
|
||||
// 捕获堆栈跟踪
|
||||
stack := debug.Stack()
|
||||
|
||||
// 记录 panic 信息
|
||||
logger.Error("Panic 已恢复",
|
||||
zap.String("request_id", requestID),
|
||||
zap.String("method", c.Method()),
|
||||
zap.String("path", c.Path()),
|
||||
zap.Any("panic", r),
|
||||
zap.String("stack", string(stack)),
|
||||
)
|
||||
|
||||
// 返回统一错误响应
|
||||
_ = response.Error(c, 500, errors.CodeInternalError, errors.GetMessage(errors.CodeInternalError, "zh"))
|
||||
}
|
||||
}()
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user