优化模块租户检查逻辑,重构数据结构并简化代码
This commit is contained in:
@@ -19,27 +19,36 @@ var (
|
||||
TenantModuleAICs = ModuleAssetId["customerService"] // AI客服模块
|
||||
)
|
||||
|
||||
// TenantModuleType 租户类型
|
||||
type TenantModuleType struct {
|
||||
type TenantModuleType string
|
||||
|
||||
const (
|
||||
TenantModuleTypePlatform TenantModuleType = "platform"
|
||||
TenantModuleTypePrivate TenantModuleType = "private"
|
||||
TenantModuleTypeSupplier TenantModuleType = "supplier"
|
||||
TenantModuleTypeSmallShop TenantModuleType = "small_shop"
|
||||
)
|
||||
|
||||
// TenantModuleTypeKV 租户类型
|
||||
type TenantModuleTypeKV struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// TenantModuleTypesAssets 资产模块租户类型
|
||||
var TenantModuleTypesAssets = []TenantModuleType{
|
||||
{Key: "private_cloud", Value: "私有云租户"},
|
||||
{Key: "supplier", Value: "供应商"},
|
||||
{Key: "small_shop", Value: "电商小店"},
|
||||
var TenantModuleTypesAssets = []TenantModuleTypeKV{
|
||||
{Key: string(TenantModuleTypePrivate), Value: "私域租户"},
|
||||
{Key: string(TenantModuleTypeSupplier), Value: "供应商"},
|
||||
{Key: string(TenantModuleTypeSmallShop), Value: "电商小店"},
|
||||
}
|
||||
|
||||
// TenantModuleTypesAd 广告模块租户类型(待定)
|
||||
var TenantModuleTypesAd []TenantModuleType
|
||||
var TenantModuleTypesAd []TenantModuleTypeKV
|
||||
|
||||
// TenantModuleTypesAICs AI客服模块租户类型(待定)
|
||||
var TenantModuleTypesAICs []TenantModuleType
|
||||
var TenantModuleTypesAICs []TenantModuleTypeKV
|
||||
|
||||
// GetTenantModuleTypes 获取模块的租户类型列表
|
||||
func GetTenantModuleTypes(module string) []TenantModuleType {
|
||||
func GetTenantModuleTypes(module string) []TenantModuleTypeKV {
|
||||
switch module {
|
||||
case TenantModuleAssets:
|
||||
return TenantModuleTypesAssets
|
||||
@@ -48,7 +57,7 @@ func GetTenantModuleTypes(module string) []TenantModuleType {
|
||||
case TenantModuleAICs:
|
||||
return TenantModuleTypesAICs
|
||||
default:
|
||||
return []TenantModuleType{}
|
||||
return []TenantModuleTypeKV{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,21 +68,14 @@ type ModuleTenantCheckReq struct {
|
||||
|
||||
// ModuleTenantCheckRes 调用admin-go设置模块租户关系的响应
|
||||
type ModuleTenantCheckRes struct {
|
||||
Status string `json:"status"` // 开通状态:activated(已开通)、expired(已到期)、not_activated(未开通)
|
||||
Message string `json:"message"` // 状态描述
|
||||
OpenStatus bool `json:"openStatus"` // 开通状态
|
||||
Status bool `json:"status"`
|
||||
CertificationStatus bool `json:"certificationStatus"`
|
||||
Message string `json:"message"` // 状态描述
|
||||
}
|
||||
|
||||
// ModuleTenant 模块租户关系实体(引用自admin-go)
|
||||
type ModuleTenant struct {
|
||||
Id uint64 `json:"id" description:""`
|
||||
CreateBy uint64 `json:"createBy" description:"创建者"`
|
||||
UpdateBy uint64 `json:"updateBy" description:"更新者"`
|
||||
CreatedAt *gtime.Time `json:"createdAt" description:"创建时间"`
|
||||
UpdatedAt *gtime.Time `json:"updatedAt" description:"更新时间"`
|
||||
ModuleKey string `json:"moduleKey" description:"模块Key"`
|
||||
TenantId uint64 `json:"tenantId" description:"租户ID"`
|
||||
ExpireAt *gtime.Time `json:"expireAt" description:"到期时间"`
|
||||
AssetId string `json:"assetId" description:"资产ID"`
|
||||
AssetSkuId string `json:"assetSkuId" description:"资产SKU ID"`
|
||||
ExpireAt *gtime.Time `json:"expireAt" description:"到期时间"`
|
||||
TenantModuleType TenantModuleType `json:"tenantModuleType" description:"租户模块类型"`
|
||||
CertificationStatus int `json:"certificationStatus" description:"认证状态"`
|
||||
}
|
||||
|
||||
@@ -13,21 +13,15 @@ import (
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func ModuleTenantCheck(r *ghttp.Request) {
|
||||
//将 http.Header 转换为 map[string]string
|
||||
headers := make(map[string]string)
|
||||
for k, v := range r.Request.Header {
|
||||
if len(v) > 0 {
|
||||
headers[k] = v[0]
|
||||
}
|
||||
}
|
||||
// 检查是否是超级管理员
|
||||
isSuperAdmin := false
|
||||
if err := nats.CallRPC(r.Context(), "userService.IsSuperAdmin", nil, &isSuperAdmin); err != nil {
|
||||
SetResponseInfo(r.Context(), r, err)
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, err)
|
||||
}
|
||||
// 如果是超级管理员,则不进行模块租户检查
|
||||
if isSuperAdmin || r.Request.RequestURI == "/asset/getAssetAndSku?assetId=696b4acd1be1c8b76c4b4c15" {
|
||||
@@ -36,7 +30,7 @@ func ModuleTenantCheck(r *ghttp.Request) {
|
||||
}
|
||||
getUserInfo, err := utils.GetUserInfo(r.Context())
|
||||
if err != nil {
|
||||
SetResponseInfo(r.Context(), r, err)
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, err)
|
||||
}
|
||||
exit := gconv.Int64(time.Minute * 1)
|
||||
getEX, err := message.GetRedisClientTest("test").GetEX(r.Context(), fmt.Sprintf("module_tenant:tenantId-%v", getUserInfo.TenantId), gredis.GetEXOption{
|
||||
@@ -45,34 +39,30 @@ func ModuleTenantCheck(r *ghttp.Request) {
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
SetResponseInfo(r.Context(), r, err)
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, err)
|
||||
}
|
||||
// 获取模块key
|
||||
moduleKey := g.Cfg().MustGet(context.Background(), "server.name").String()
|
||||
if !g.IsEmpty(getEX.String()) {
|
||||
list := make([]beans.ModuleTenant, 0)
|
||||
if err = json.Unmarshal([]byte(getEX.String()), &list); err != nil {
|
||||
SetResponseInfo(r.Context(), r, err)
|
||||
}
|
||||
var expireAt *gtime.Time
|
||||
for _, value := range list {
|
||||
if value.ModuleKey == moduleKey {
|
||||
expireAt = value.ExpireAt
|
||||
break
|
||||
}
|
||||
list := new(beans.ModuleTenant)
|
||||
if err = json.Unmarshal(getEX.Bytes(), &list); err != nil {
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, err)
|
||||
}
|
||||
// 缓存中有数据,检查是否过期
|
||||
if !g.IsEmpty(expireAt) {
|
||||
if !g.IsEmpty(list.ExpireAt) {
|
||||
gt1 := gtime.New(time.Now())
|
||||
gt2 := gtime.New(expireAt)
|
||||
gt2 := gtime.New(list.ExpireAt)
|
||||
if !gt1.Before(gt2) {
|
||||
SetResponseInfo(r.Context(), r, "您访问的模块已过期,请续期后再使用")
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, "功能模块已到期,请续期后再使用")
|
||||
} else {
|
||||
if list.CertificationStatus != 2 {
|
||||
SetResponseInfo(r.Context(), r, http.StatusPreconditionRequired, "功能模块未认证通过,请认证后再使用")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SetResponseInfo(r.Context(), r, "您未开通此模块,请开通后再使用")
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, "您未开通此功能模块,请开通后再使用")
|
||||
}
|
||||
} else {
|
||||
// 缓存为空,调用admin-go的Check接口检查模块开通状态
|
||||
checkRes := new(beans.ModuleTenantCheckRes)
|
||||
checkReq := beans.ModuleTenantCheckReq{
|
||||
ModuleKey: moduleKey,
|
||||
@@ -80,25 +70,27 @@ func ModuleTenantCheck(r *ghttp.Request) {
|
||||
}
|
||||
err = nats.CallRPC(r.Context(), "moduleService.Check", &checkReq, checkRes)
|
||||
if err != nil {
|
||||
SetResponseInfo(r.Context(), r, err)
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, err)
|
||||
}
|
||||
// 根据检查结果判断是否允许访问
|
||||
if checkRes.Status == "not_activated" {
|
||||
SetResponseInfo(r.Context(), r, "您未开通此模块,请开通后再使用")
|
||||
} else if checkRes.Status == "expired" {
|
||||
SetResponseInfo(r.Context(), r, "您访问的模块已过期,请续期后再使用")
|
||||
if !checkRes.Status {
|
||||
SetResponseInfo(r.Context(), r, http.StatusPaymentRequired, checkRes.Message)
|
||||
} else {
|
||||
if !checkRes.CertificationStatus {
|
||||
SetResponseInfo(r.Context(), r, http.StatusPreconditionRequired, checkRes.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r.Middleware.Next() // 继续执行后续中间件和路由处理
|
||||
}
|
||||
|
||||
// SetResponseInfo 设置响应信息
|
||||
func SetResponseInfo(ctx context.Context, r *ghttp.Request, message any) {
|
||||
func SetResponseInfo(ctx context.Context, r *ghttp.Request, code int, message any) {
|
||||
_ = ctx
|
||||
r.Response.Status = 402
|
||||
r.Response.WriteJsonExit(map[string]interface{}{
|
||||
"success": false,
|
||||
"code": 402,
|
||||
"code": code,
|
||||
"message": fmt.Sprintf("服务不可用:%s", message),
|
||||
})
|
||||
r.Exit()
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"gitee.com/red-future---jilin-g/common/log/consts"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/beans"
|
||||
@@ -643,7 +642,7 @@ func (m *MongoDB) SaveOrUpdate(ctx context.Context, filter []bson.M, update []bs
|
||||
return bulkResult, nil
|
||||
}
|
||||
|
||||
func BuildUpdateFilter(ctx context.Context, req interface{}) (filter bson.M, err error) {
|
||||
func BuildUpdateData(ctx context.Context, req interface{}) (filter bson.M, err error) {
|
||||
_ = ctx
|
||||
filter = bson.M{}
|
||||
reqMap := gconv.Map(req)
|
||||
@@ -654,55 +653,3 @@ func BuildUpdateFilter(ctx context.Context, req interface{}) (filter bson.M, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// EntityToBson 将 *entity/entity 转换为 bson.M
|
||||
func EntityToBson(entity interface{}) (bson.M, error) {
|
||||
return EntityToBsonWithFilter(entity, false)
|
||||
}
|
||||
|
||||
// EntityToBsonWithFilter 将 *entity/entity 转换为 bson.M,并可选择是否过滤空值
|
||||
func EntityToBsonWithFilter(entity interface{}, filterEmpty bool) (bson.M, error) {
|
||||
if entity == nil {
|
||||
return nil, fmt.Errorf("传入的 entity 实例为 nil")
|
||||
}
|
||||
bsonBytes, err := bson.Marshal(entity)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("entity 序列化为 BSON 字节流失败:%w", err)
|
||||
}
|
||||
var bsonMap bson.M
|
||||
err = bson.Unmarshal(bsonBytes, &bsonMap)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("BSON 字节流反序列化为 bson.M 失败:%w", err)
|
||||
}
|
||||
if filterEmpty {
|
||||
for key, value := range bsonMap {
|
||||
if isEmptyWithZero(value) {
|
||||
delete(bsonMap, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
return bsonMap, nil
|
||||
}
|
||||
|
||||
// isEmptyWithZero 判断是否为空值,但保留 int 类型的 0 值
|
||||
func isEmptyWithZero(value interface{}) bool {
|
||||
if value == nil {
|
||||
return true
|
||||
}
|
||||
rv := reflect.ValueOf(value)
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
if rv.IsNil() {
|
||||
return true
|
||||
}
|
||||
kind = rv.Elem().Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Float32, reflect.Float64:
|
||||
return false
|
||||
default:
|
||||
return g.IsEmpty(value)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user