From 9e01f95a6143771f2d7328e444cb3f3750bbc441 Mon Sep 17 00:00:00 2001 From: richjohnrambo Date: Fri, 25 Sep 2026 23:26:54 +0800 Subject: [PATCH] fix: allow bound tenant option loading --- .../internal/logic/middleware/admin_auth.go | 7 ++++++ server/internal/logic/sys/im_tenant.go | 23 +++++++++++++++++++ web/src/views/imTenantOptions.ts | 21 +++++++---------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/server/internal/logic/middleware/admin_auth.go b/server/internal/logic/middleware/admin_auth.go index 6533843..52073c1 100644 --- a/server/internal/logic/middleware/admin_auth.go +++ b/server/internal/logic/middleware/admin_auth.go @@ -42,6 +42,13 @@ func (s *sMiddleware) AdminAuth(r *ghttp.Request) { return } + // 已绑定 IM 租户的后台账号需要读取自己的租户选项,用于各 IM 页面初始化租户下拉。 + // 业务层会继续按登录态 tenant_id 收敛查询范围,这里只绕过菜单权限,不扩大数据范围。 + if path == "/imTenant/list" && r.Method == "GET" && contexts.GetTenantId(ctx) > 0 { + r.Middleware.Next() + return + } + // 验证路由访问权限 if !service.AdminRole().Verify(ctx, path, r.Method) { g.Log().Debugf(ctx, "AdminAuth fail path:%+v, GetRoleKey:%+v, r.Method:%+v", path, contexts.GetRoleKey(ctx), r.Method) diff --git a/server/internal/logic/sys/im_tenant.go b/server/internal/logic/sys/im_tenant.go index 1eaa974..5a2ed6d 100644 --- a/server/internal/logic/sys/im_tenant.go +++ b/server/internal/logic/sys/im_tenant.go @@ -479,6 +479,9 @@ func (s *sSysImTenant) View(ctx context.Context, in *sysin.ImTenantViewInp) (res if err = in.Filter(ctx); err != nil { return } + if err = ensureImTenantTargetAllowed(ctx, in.Id); err != nil { + return + } if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil { err = gerror.Wrap(err, "获取IM租户信息失败,请稍后重试!") return @@ -536,6 +539,9 @@ func (s *sSysImTenant) Usage(ctx context.Context, in *sysin.ImTenantUsageInp) (r if err = in.Filter(ctx); err != nil { return } + if err = ensureImTenantTargetAllowed(ctx, in.Id); err != nil { + return + } var tenant *entity.ImTenant if err = s.Model(ctx).WherePri(in.Id).Scan(&tenant); err != nil { @@ -577,6 +583,23 @@ func (s *sSysImTenant) Usage(ctx context.Context, in *sysin.ImTenantUsageInp) (r return } +func ensureImTenantTargetAllowed(ctx context.Context, tenantId int64) error { + if isImPlatformAdmin(ctx, contexts.GetUserId(ctx)) { + return nil + } + if tenantId <= 0 { + return gerror.New("商户ID不能为空") + } + boundTenantId := contexts.GetTenantId(ctx) + if boundTenantId <= 0 { + return gerror.New("当前管理员未关联IM租户") + } + if tenantId != boundTenantId { + return gerror.New("无权访问其它商户") + } + return nil +} + func (s *sSysImTenant) queryScalarInt64(ctx context.Context, db gdb.DB, label, sql string, warnings *[]string, args ...any) int64 { value, err := db.GetValue(ctx, sql, args...) if err != nil { diff --git a/web/src/views/imTenantOptions.ts b/web/src/views/imTenantOptions.ts index c7d315d..a9f28cd 100644 --- a/web/src/views/imTenantOptions.ts +++ b/web/src/views/imTenantOptions.ts @@ -31,17 +31,8 @@ export async function loadImTenantOptions( // 登录用户已绑定商户租户:仅返回自己商户选项(与后端 resolveImAdminScope 强制范围一致) if (boundTenantId > 0) { - let tenant: any = null; - try { - const res = await TenantList({ ...params, id: boundTenantId, page: 1, perPage: 1 }); - tenant = (res?.list || []).find((item) => Number(item.id) === boundTenantId); - } catch { - tenant = null; - } - if (!tenant) { - const info = readTokenUserInfo(useUserStore().getToken); - tenant = { id: boundTenantId, name: info?.tenantName, code: info?.tenantCode }; - } + const info = readCurrentUserInfo(); + const tenant = { id: boundTenantId, name: info?.tenantName, code: info?.tenantCode }; target.value = [toTenantOption(tenant)]; return target.value; } @@ -58,8 +49,7 @@ export async function loadImTenantOptions( // 登录用户绑定的商户租户ID(按绑定租户判定,与后端 resolveImAdminScope 的范围逻辑一致) export function getBoundTenantId(): number { - const userStore = useUserStore(); - const userInfo = { ...readTokenUserInfo(userStore.getToken), ...(userStore.getUserInfo as any) }; + const userInfo = readCurrentUserInfo(); return Number(userInfo?.tenantId || userInfo?.tenantID || 0); } @@ -109,6 +99,11 @@ function toTenantOption(item: any): ImTenantOption { }; } +function readCurrentUserInfo() { + const userStore = useUserStore(); + return { ...readTokenUserInfo(userStore.getToken), ...(userStore.getUserInfo as any) }; +} + function readTokenUserInfo(token: string) { try { const payload = token.split('.')[1];