优化限流功能
This commit is contained in:
@@ -209,6 +209,8 @@ func (m *HalfOpenManager) checkHalfOpenSuccessThreshold(metrics HalfOpenMetrics,
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 使用浮点数除法计算成功率,避免整数除法精度丢失问题
|
||||||
|
// 例如: passedRequests=1, failedRequests=2, 则 successRate = 0.333... 而不是 0
|
||||||
successRate := float64(passedRequests) / float64(totalRequests)
|
successRate := float64(passedRequests) / float64(totalRequests)
|
||||||
return successRate >= successThreshold
|
return successRate >= successThreshold
|
||||||
}
|
}
|
||||||
@@ -1106,32 +1108,74 @@ func syncCircuitBreakerStateToDistributed(ctx context.Context, resourceName, sta
|
|||||||
g.Log().Warningf(ctx, "分布式熔断状态同步失败,跳过: %s, 最后错误: %v", lockKey, lastErr)
|
g.Log().Warningf(ctx, "分布式熔断状态同步失败,跳过: %s, 最后错误: %v", lockKey, lastErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CircuitBreakerHealthCheckHandler 健康检查接口
|
// checkCircuitBreakerAuthToken 验证熔断器管理接口的认证Token
|
||||||
func CircuitBreakerHealthCheckHandler(r *ghttp.Request) {
|
// 统一的认证逻辑,用于健康检查、重置等管理接口
|
||||||
// 添加认证检查:使用JWT Token或API Key
|
// 返回值:
|
||||||
|
// - true: 认证通过
|
||||||
|
// - false: 认证失败,已发送401响应
|
||||||
|
func checkCircuitBreakerAuthToken(r *ghttp.Request) bool {
|
||||||
// 从Header中获取认证信息
|
// 从Header中获取认证信息
|
||||||
authToken := r.Header.Get("Authorization")
|
authToken := r.Header.Get("Authorization")
|
||||||
|
|
||||||
|
// 如果Header中没有,尝试从查询参数获取(仅用于开发/测试环境)
|
||||||
|
// 生产环境应禁用此方式,仅支持Header认证
|
||||||
if authToken == "" {
|
if authToken == "" {
|
||||||
// 尝试从查询参数获取(仅用于开发环境)
|
|
||||||
authToken = r.Get("authToken").String()
|
authToken = r.Get("authToken").String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简单的Token验证(生产环境应使用更严格的认证)
|
// 检查Token是否为空
|
||||||
// 建议使用JWT或其他安全的认证机制
|
|
||||||
if authToken == "" {
|
if authToken == "" {
|
||||||
g.Log().Warningf(r.GetCtx(), "熔断器健康检查被拒绝:缺少认证信息,IP=%s", r.GetClientIp())
|
g.Log().Warningf(r.GetCtx(), "熔断器管理接口访问被拒绝:缺少认证Token, IP=%s, Path=%s",
|
||||||
|
r.GetClientIp(), r.URL.Path)
|
||||||
r.Response.WriteStatusExit(401, "Unauthorized: Missing authentication token")
|
r.Response.WriteStatusExit(401, "Unauthorized: Missing authentication token")
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 在这里添加真正的Token验证逻辑
|
// 支持Bearer Token格式
|
||||||
// 示例:使用JWT验证
|
if strings.HasPrefix(authToken, "Bearer ") {
|
||||||
// claims, err := jwt.ParseWithClaims(authToken, &MyClaims{})
|
authToken = strings.TrimPrefix(authToken, "Bearer ")
|
||||||
// if err != nil {
|
}
|
||||||
|
|
||||||
|
// TODO: 实现完整的Token验证逻辑
|
||||||
|
// 建议使用JWT或其他安全机制:
|
||||||
|
//
|
||||||
|
// 1. 使用gogf/gf/v2/os/gjwt进行JWT验证:
|
||||||
|
// token, err := gjwt.ParseAndVerify(authToken, []byte(secret))
|
||||||
|
// if err != nil {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// 2. 或使用其他JWT库(如github.com/golang-jwt/jwt/v5):
|
||||||
|
// claims := &MyClaims{}
|
||||||
|
// token, err := jwt.ParseWithClaims(authToken, claims, ...)
|
||||||
|
//
|
||||||
|
// 3. 验证Token的:
|
||||||
|
// - 签名有效性
|
||||||
|
// - 过期时间(exp)
|
||||||
|
// - 签发者(iss)
|
||||||
|
// - 权限范围(scope/roles)
|
||||||
|
//
|
||||||
|
// 4. 从Token中提取用户/服务信息存储到context供后续使用
|
||||||
|
|
||||||
|
// 当前为简化实现,仅检查Token非空
|
||||||
|
// 生产环境必须替换为真实的Token验证逻辑
|
||||||
|
// 示例:使用validateToken函数(需在其他地方实现)
|
||||||
|
// if !validateToken(authToken) {
|
||||||
|
// g.Log().Warningf(r.GetCtx(), "熔断器管理接口访问被拒绝:无效的认证Token, IP=%s", r.GetClientIp())
|
||||||
// r.Response.WriteStatusExit(401, "Unauthorized: Invalid token")
|
// r.Response.WriteStatusExit(401, "Unauthorized: Invalid token")
|
||||||
// return
|
// return false
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// CircuitBreakerHealthCheckHandler 健康检查接口
|
||||||
|
func CircuitBreakerHealthCheckHandler(r *ghttp.Request) {
|
||||||
|
// 认证检查:使用Token验证
|
||||||
|
if !checkCircuitBreakerAuthToken(r) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
page := r.Get("page").Int()
|
page := r.Get("page").Int()
|
||||||
size := r.Get("size").Int()
|
size := r.Get("size").Int()
|
||||||
if page < 0 {
|
if page < 0 {
|
||||||
@@ -1237,20 +1281,11 @@ func batchProcessResources(r *ghttp.Request, processFunc func(resourceName strin
|
|||||||
|
|
||||||
// CircuitBreakerResetHandler 重置熔断器
|
// CircuitBreakerResetHandler 重置熔断器
|
||||||
func CircuitBreakerResetHandler(r *ghttp.Request) {
|
func CircuitBreakerResetHandler(r *ghttp.Request) {
|
||||||
// 添加认证检查(与健康检查接口相同)
|
// 认证检查
|
||||||
authToken := r.Header.Get("Authorization")
|
if !checkCircuitBreakerAuthToken(r) {
|
||||||
if authToken == "" {
|
|
||||||
authToken = r.Get("authToken").String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if authToken == "" {
|
|
||||||
g.Log().Warningf(r.GetCtx(), "熔断器重置被拒绝:缺少认证信息,IP=%s", r.GetClientIp())
|
|
||||||
r.Response.WriteStatusExit(401, "Unauthorized: Missing authentication token")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 添加真正的Token验证逻辑
|
|
||||||
|
|
||||||
resourceName := r.Get("resource").String()
|
resourceName := r.Get("resource").String()
|
||||||
|
|
||||||
if resourceName == "" || resourceName == "*" {
|
if resourceName == "" || resourceName == "*" {
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ func Auth(r *ghttp.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证 token
|
// 验证 token
|
||||||
|
// TODO: 实现完整的JWT验证逻辑
|
||||||
|
// 当前为占位实现,实际使用时应替换为真实的token验证
|
||||||
|
// 例如:使用gogf/gf/v2/os/gjwt或其他JWT库进行验证
|
||||||
if !validateToken(gstr.SubStrFrom(token, "7")) {
|
if !validateToken(gstr.SubStrFrom(token, "7")) {
|
||||||
r.Response.WriteStatusExit(401, "Unauthorized")
|
r.Response.WriteStatusExit(401, "Unauthorized")
|
||||||
return
|
return
|
||||||
@@ -37,3 +40,44 @@ func Auth(r *ghttp.Request) {
|
|||||||
|
|
||||||
r.Middleware.Next()
|
r.Middleware.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validateToken 验证Token有效性
|
||||||
|
// 当前为简化实现,实际生产环境应使用JWT或其他安全机制进行验证
|
||||||
|
// 示例:
|
||||||
|
// - 使用gogf/gf/v2/os/gjwt库解析和验证JWT token
|
||||||
|
// - 验证token签名、过期时间、签发者等
|
||||||
|
// - 从token中提取用户信息并存储到context
|
||||||
|
//
|
||||||
|
// 返回值:
|
||||||
|
// - true: token有效
|
||||||
|
// - false: token无效或过期
|
||||||
|
func validateToken(token string) bool {
|
||||||
|
// TODO: 实现真实的token验证逻辑
|
||||||
|
// 当前为占位实现,返回true以允许基本功能运行
|
||||||
|
// 生产环境必须替换为真实的验证逻辑
|
||||||
|
|
||||||
|
// 简单的非空检查
|
||||||
|
if token == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 建议的JWT验证示例(需要引入jwt库):
|
||||||
|
/*
|
||||||
|
claims := &jwt.MapClaims{}
|
||||||
|
t, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte("your-secret-key"), nil
|
||||||
|
})
|
||||||
|
if err != nil || !t.Valid {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 检查过期时间
|
||||||
|
if exp, ok := (*claims)["exp"].(float64); ok {
|
||||||
|
if time.Now().Unix() > int64(exp) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 临时返回true,实际使用时应实现完整验证
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,13 +11,9 @@ const (
|
|||||||
|
|
||||||
// 限流 Redis Key 常量
|
// 限流 Redis Key 常量
|
||||||
const (
|
const (
|
||||||
RateLimitKeyPrefix = "ragflow:ratelimit:" // 限流Key前缀
|
RateLimitKeyPrefix = "ragflow:ratelimit:" // 限流Key前缀
|
||||||
RateLimitKeyIP = "ip:%s" // IP限流: ip:192.168.1.1
|
RateLimitKeyIP = "ip:%s" // IP限流: ip:192.168.1.1
|
||||||
RateLimitKeyUser = "user:%s" // 用户限流: user:123 或 user:anon:192.168.1.1
|
RateLimitKeyUser = "user:%s" // 用户限流: user:123 或 user:anon:192.168.1.1
|
||||||
RateLimitKeyService = "service:%s" // 服务限流: service:customerService
|
RateLimitKeyService = "service:%s" // 服务限流: service:customerService
|
||||||
RateLimitKeyGlobal = "global:requests" // 全局限流: global:requests
|
RateLimitKeyGlobal = "global:requests" // 全局限流: global:requests
|
||||||
RateLimitKeyOrder = "order:create:%s" // 订单创建限流: order:create:123
|
|
||||||
RateLimitKeyTransfer = "wallet:transfer:%s" // 钱包转账限流: wallet:transfer:123
|
|
||||||
RateLimitKeyMessage = "cs:message:%s" // 客服消息限流: cs:message:123
|
|
||||||
RateLimitKeyUpload = "oss:upload:%s" // 文件上传限流: oss:upload:123
|
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user