* 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>
56 lines
1.5 KiB
Go
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
|
|
}
|