Files
79b9224968 注册功能优化 (#10)
* fix:修复权限问题

* fix:修复项目key类型错误问题

* fix:修复rbac权限问题

* fix:修复api密钥未及时失效的问题

* improve:优化渠道调度稳定性

* improve:优化路由

* fix:修复项目预算控制缺陷

* fix:加强限流等安全措施

* feat:添加限流相关字段的前端展示及接口字段

* improve:优化注册时密码要求,只需要字母和数字即可

* feat(setting):添加注册限流设置

* improve:优化前端数字类型转换

* chore:rbac权限放行

* feat:团队功能作为可选项,允许不设置团队的情况下进行注册

* feat:团队code只能设置一次

* improve:优化组织名称限制

* chore:合并数据库版本文件

---------

Co-authored-by: chengqian <wuchengqian@kkidc.com>
Co-authored-by: qian <wuchengqian5@163.com>
2026-06-23 23:07:36 +08:00

56 lines
1.5 KiB
Go

package tenant
import (
"context"
"crypto/rand"
"fmt"
"math/big"
"github.com/gogf/gf/v2/frame/g"
"github.com/qianfree/team-api/internal/dao"
)
// generateUniqueTenantCode 生成一个不冲突的默认租户 code。
// 格式:org-<base36>,满足正则 ^[a-z0-9][a-z0-9-]*[a-z0-9]$,长度 3-30。
// 用 crypto/rand 保证不可预测,循环查重最多 5 次避免唯一索引冲突。
func generateUniqueTenantCode(ctx context.Context) (string, error) {
const maxAttempts = 5
for i := 0; i < maxAttempts; i++ {
code, err := randomTenantCode()
if err != nil {
return "", err
}
count, err := dao.TntTenants.Ctx(ctx).Where("code", code).Count()
if err != nil {
return "", err
}
if count == 0 {
return code, nil
}
g.Log().Warningf(ctx, "生成的租户 code 冲突,重试: %s", code)
}
return "", fmt.Errorf("生成唯一租户 code 失败(重试 %d 次)", maxAttempts)
}
// randomTenantCode 生成单个 "org-<base36>" 形式的随机 code。
func randomTenantCode() (string, error) {
b := make([]byte, 9)
if _, err := rand.Read(b); err != nil {
return "", err
}
const alphabet = "0123456789abcdefghijklmnopqrstuvwxyz"
var chars []byte
tmp := new(big.Int).SetBytes(b)
base := big.NewInt(36)
mod := new(big.Int)
for tmp.Sign() > 0 && len(chars) < 16 {
tmp.DivMod(tmp, base, mod)
chars = append([]byte{alphabet[mod.Int64()]}, chars...)
}
if len(chars) == 0 {
chars = []byte{'0'}
}
return "org-" + string(chars), nil
}