feat(distribution): 支持分站独立短信验证码通道

- 新增分销站点独立短信服务商配置(阿里云),登录验证码按 site_code/domain
  解析专属通道,未启用或解析失败时回退主站默认通道
- 密钥经 crypto.Encryptor 加密落库,模型字段 json 序列化隔离,DTO 仅回传掩码
- provider 白名单校验,mock 仅在非生产环境放行;启用时强制校验必填凭据
- 配置读写/测试接口限管理员权限,测试发送增加 60s 频控(Redis,缺省进程内)
- 解密失败记告警并优雅回退主站,避免把密文当明文密钥使用
- 两套前端新增短信配置入口、必填与手机号校验、发送冷却
- 新增迁移 000071 及加解密、白名单、频控、解析回退等单测
This commit is contained in:
yml2213
2026-09-16 14:06:01 +08:00
parent aef858f399
commit dc13b5dc82
16 changed files with 1971 additions and 14 deletions
+12
View File
@@ -317,8 +317,17 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
var distributionRepo *distribution.Repository
if deps.DB != nil {
distributionRepo = distribution.NewRepository(deps.DB, deps.Redis)
distributionRepo.SetEncryptor(fieldEncryptor)
distributionRepo.SetAllowMockSMS(!config.IsProductionEnv(cfg.AppEnv))
}
distributionService := distribution.NewService(distributionRepo, jwtManager)
if distributionRepo != nil {
distributionResolver := distribution.NewSMSResolver(distributionRepo, logger)
distributionService.SetSMSResolver(distributionResolver)
if authService != nil {
authService.SetSiteSMSResolver(distributionService)
}
}
distributionHandler := distribution.NewHandler(distributionService)
backupMonitorHandler := backupmonitor.NewHandler(cfg.BackupStatusFile)
var adminRoleRepo *adminrole.Repository
@@ -647,6 +656,9 @@ func New(cfg config.Config, deps Dependencies, logger *zap.Logger) *gin.Engine {
adminRoutes.POST("/distribution/sites/:id/sync-accounts", requirePerm("distribution:account_display"), distributionHandler.SyncSiteAccounts)
adminRoutes.PUT("/distribution/sites/:id", requirePerm("distribution:site_manage"), distributionHandler.UpdateSite)
adminRoutes.PUT("/distribution/sites/:id/branding", requirePerm("distribution:site_manage"), distributionHandler.UpdateSiteBranding)
adminRoutes.GET("/distribution/sites/:id/sms-config", requirePerm("distribution:site_view"), distributionHandler.GetSiteSMSConfig)
adminRoutes.PUT("/distribution/sites/:id/sms-config", requirePerm("distribution:site_manage"), distributionHandler.UpdateSiteSMSConfig)
adminRoutes.POST("/distribution/sites/:id/sms-config/test", requirePerm("distribution:site_manage"), distributionHandler.TestSiteSMSConfig)
adminRoutes.GET("/distribution/sites/:id/wallet", requirePerm("distribution:settlement_view"), distributionHandler.GetSiteWallet)
adminRoutes.POST("/distribution/sites/:id/withdrawals", requirePerm("distribution:settlement_manage"), distributionHandler.ApplySiteWithdrawal)
adminRoutes.GET("/distribution/sites/:id/withdrawals", requirePerm("distribution:settlement_view"), distributionHandler.ListSiteWithdrawals)