实现个人客户微信认证和短信验证功能

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-10 11:42:38 +08:00
parent 1b9080e3ab
commit 9c6d4a3bd4
53 changed files with 4258 additions and 97 deletions

View File

@@ -18,6 +18,8 @@ type Config struct {
Queue QueueConfig `mapstructure:"queue"`
Logging LoggingConfig `mapstructure:"logging"`
Middleware MiddlewareConfig `mapstructure:"middleware"`
SMS SMSConfig `mapstructure:"sms"`
JWT JWTConfig `mapstructure:"jwt"`
}
// ServerConfig HTTP 服务器配置
@@ -94,6 +96,21 @@ type RateLimiterConfig struct {
Storage string `mapstructure:"storage"` // "memory" 或 "redis"
}
// SMSConfig 短信服务配置
type SMSConfig struct {
GatewayURL string `mapstructure:"gateway_url"` // 短信网关地址
Username string `mapstructure:"username"` // 账号用户名
Password string `mapstructure:"password"` // 账号密码
Signature string `mapstructure:"signature"` // 短信签名(例如:【签名】)
Timeout time.Duration `mapstructure:"timeout"` // 请求超时时间
}
// JWTConfig JWT 认证配置
type JWTConfig struct {
SecretKey string `mapstructure:"secret_key"` // JWT 签名密钥
TokenDuration time.Duration `mapstructure:"token_duration"` // Token 有效期
}
// Validate 验证配置值
func (c *Config) Validate() error {
// 服务器验证
@@ -158,6 +175,34 @@ func (c *Config) Validate() error {
return fmt.Errorf("invalid configuration: middleware.rate_limiter.storage: invalid storage type (current value: %s, expected: memory or redis)", c.Middleware.RateLimiter.Storage)
}
// 短信服务验证
if c.SMS.GatewayURL == "" {
return fmt.Errorf("invalid configuration: sms.gateway_url: must be non-empty (current value: empty)")
}
if c.SMS.Username == "" {
return fmt.Errorf("invalid configuration: sms.username: must be non-empty (current value: empty)")
}
if c.SMS.Password == "" {
return fmt.Errorf("invalid configuration: sms.password: must be non-empty (current value: empty)")
}
if c.SMS.Signature == "" {
return fmt.Errorf("invalid configuration: sms.signature: must be non-empty (current value: empty)")
}
if c.SMS.Timeout < 5*time.Second || c.SMS.Timeout > 60*time.Second {
return fmt.Errorf("invalid configuration: sms.timeout: duration out of range (current value: %s, expected: 5s-60s)", c.SMS.Timeout)
}
// JWT 验证
if c.JWT.SecretKey == "" {
return fmt.Errorf("invalid configuration: jwt.secret_key: must be non-empty (current value: empty)")
}
if len(c.JWT.SecretKey) < 32 {
return fmt.Errorf("invalid configuration: jwt.secret_key: secret key too short (current length: %d, expected: >= 32)", len(c.JWT.SecretKey))
}
if c.JWT.TokenDuration < 1*time.Hour || c.JWT.TokenDuration > 720*time.Hour {
return fmt.Errorf("invalid configuration: jwt.token_duration: duration out of range (current value: %s, expected: 1h-720h)", c.JWT.TokenDuration)
}
return nil
}