Files
junhong_cmp_fiber/internal/middleware/personal_auth.go
huang 9c6d4a3bd4 实现个人客户微信认证和短信验证功能
- 添加个人客户微信登录和手机验证码登录接口
- 实现个人客户设备、ICCID、手机号关联管理
- 添加短信发送服务(HTTP 客户端)
- 添加微信认证服务(含 mock 实现)
- 添加 JWT Token 生成和验证工具
- 创建数据库迁移脚本(personal_customer 关联表)
- 修复测试文件中的路由注册参数错误
- 重构 scripts 目录结构(分离独立脚本到子目录)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-10 11:42:38 +08:00

90 lines
2.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package middleware
import (
"strings"
"github.com/break/junhong_cmp_fiber/pkg/auth"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
// PersonalAuthMiddleware 个人客户认证中间件
type PersonalAuthMiddleware struct {
jwtManager *auth.JWTManager
logger *zap.Logger
}
// NewPersonalAuthMiddleware 创建个人客户认证中间件
func NewPersonalAuthMiddleware(jwtManager *auth.JWTManager, logger *zap.Logger) *PersonalAuthMiddleware {
return &PersonalAuthMiddleware{
jwtManager: jwtManager,
logger: logger,
}
}
// Authenticate 认证中间件
func (m *PersonalAuthMiddleware) Authenticate() fiber.Handler {
return func(c *fiber.Ctx) error {
// 从 Authorization header 获取 token
authHeader := c.Get("Authorization")
if authHeader == "" {
m.logger.Warn("个人客户认证失败:缺少 Authorization header",
zap.String("path", c.Path()),
zap.String("method", c.Method()),
)
return errors.New(errors.CodeUnauthorized, "未提供认证令牌")
}
// 检查 Bearer 前缀
parts := strings.SplitN(authHeader, " ", 2)
if len(parts) != 2 || parts[0] != "Bearer" {
m.logger.Warn("个人客户认证失败Authorization header 格式错误",
zap.String("path", c.Path()),
zap.String("auth_header", authHeader),
)
return errors.New(errors.CodeUnauthorized, "认证令牌格式错误")
}
token := parts[1]
// 验证 token
claims, err := m.jwtManager.VerifyPersonalCustomerToken(token)
if err != nil {
m.logger.Warn("个人客户认证失败token 验证失败",
zap.String("path", c.Path()),
zap.Error(err),
)
return errors.New(errors.CodeUnauthorized, "认证令牌无效或已过期")
}
// 将客户信息存储到 context 中
c.Locals("customer_id", claims.CustomerID)
c.Locals("customer_phone", claims.Phone)
// 设置 SkipOwnerFilter 标记,跳过 B 端数据权限过滤
// 个人客户不参与 RBAC 权限体系,不需要 Owner 过滤
c.Locals("skip_owner_filter", true)
m.logger.Debug("个人客户认证成功",
zap.Uint("customer_id", claims.CustomerID),
zap.String("phone", claims.Phone),
zap.String("path", c.Path()),
)
return c.Next()
}
}
// GetCustomerID 从 context 中获取当前个人客户 ID
func GetCustomerID(c *fiber.Ctx) (uint, bool) {
customerID, ok := c.Locals("customer_id").(uint)
return customerID, ok
}
// GetCustomerPhone 从 context 中获取当前个人客户手机号
func GetCustomerPhone(c *fiber.Ctx) (string, bool) {
phone, ok := c.Locals("customer_phone").(string)
return phone, ok
}