平台后台和商家后台权限怎么隔离?一次讲清账号体系、菜单边界、租户隔离与数据权限设计

大家好,我是一名有 4 年工作经验的 Java 后端开发。
最近在系统整理电商后台和权限系统里的实战问题,准备沉淀成一个系列。
前面两篇我写了电商后台的菜单权限、按钮权限、数据权限怎么设计,以及电商系统的数据权限 SQL 应该怎么做,这一篇继续往下拆一个特别关键、也特别容易做乱的话题:平台后台和商家后台权限怎么隔离。

🦅个人主页
🐼

文章目录


一、前言

很多团队一开始做电商后台时,往往只有一套管理后台:

  • 平台运营在用
  • 平台客服在用
  • 商家运营也在用
  • 商家仓库也在用

看起来很省事。
但业务一旦复杂起来,很快就会出现这些问题:

  • 平台运营能看到商家后台不该看到的字段
  • 商家后台菜单越来越多,很多其实是平台专属功能
  • SQL 到处加 merchant_id,最后谁都说不清该不该带
  • 同样是订单列表,平台看的是全站订单,商家看的是自己店铺订单,结果共用一套接口越写越乱
  • 权限表只有一套角色,结果平台角色和商家角色混在一起
  • 平台客服和商家客服权限模型不一样,却被迫塞到同一个角色体系里

这类问题的根源通常不是“代码写得不够细”,而是:

一开始没有把平台后台和商家后台当成两套边界不同的系统去设计。

从权限视角看,这两者最核心的区别在于:

  • 平台后台:站在平台角度管理全局资源
  • 商家后台:站在商家角度管理自己租户范围内资源

也就是说:

平台后台和商家后台,菜单边界、数据边界、角色边界、接口边界,本质上都不一样。

这篇文章就结合电商系统真实场景,把这两套权限体系到底该怎么隔离、账号体系怎么设计、数据库怎么建模、前后端怎么配合,系统讲透。


二、业务场景

先假设这样一个典型的平台型电商系统。

2.1 平台后台用户

平台后台常见角色有这些:

  • 平台超级管理员
  • 平台运营
  • 平台客服
  • 平台财务
  • 平台审核员
  • 平台风控人员

他们通常关心的是:

  • 全站商家管理
  • 商品审核
  • 平台活动配置
  • 订单全局查询
  • 平台结算
  • 违规处罚

2.2 商家后台用户

商家后台常见角色有这些:

  • 商家管理员
  • 商家运营
  • 商家客服
  • 商家仓库
  • 商家财务

他们通常关心的是:

  • 自己店铺的商品
  • 自己店铺的订单
  • 自己店铺的售后
  • 自己店铺的库存
  • 自己店铺的营销活动

2.3 真实业务要求

这个场景下,通常会有下面这些要求:

  • 平台后台可以查看全站商家订单
  • 商家后台只能查看自己的订单
  • 平台有“商家审核”“商家结算”“平台活动管理”等菜单,商家后台不应该出现
  • 商家后台有“店铺装修”“店铺商品”“商家库存”等菜单,平台角色不一定需要
  • 平台客服可以跨店铺查单,商家客服只能查自己店铺
  • 平台和商家的角色、菜单、数据权限模型应该隔离

这说明一个非常关键的问题:

平台后台和商家后台,不是同一套权限在不同角色上的缩放,而是两套边界不同的后台系统。


三、问题现象

很多项目一开始没有明确隔离,通常会出现这些典型问题。

3.1 菜单混在一起

比如一个后台菜单里既有:

  • 商家管理
  • 平台结算
  • 商品审核

又有:

  • 我的商品
  • 我的订单
  • 我的售后

这种混法最大的问题不是“看起来乱”,而是:

  • 平台和商家菜单边界不清晰
  • 权限树越来越大
  • 角色越来越难配

3.2 一套角色体系硬塞两种后台

比如权限系统里只有这些角色:

  • 管理员
  • 运营
  • 客服
  • 财务

看起来简单,但实际上:

  • 平台运营和商家运营根本不是一个权限边界
  • 平台客服和商家客服能看的数据范围完全不同

最后就会变成:

  • 角色名字相同
  • 权限配置完全不同
  • 维护成本极高

3.3 所有 SQL 都靠 merchant_id 硬拦

很多人以为只要每张业务表都加一个 merchant_id,然后查的时候加上条件就行了。

这当然是必要的一层,但它不等于完整隔离。

因为你还要面对这些问题:

  • 平台用户要不要带 merchant_id
  • 平台角色能看全部,还是看一部分商家
  • 平台审核员能看商家商品,但商家不能看别家商品
  • 某些平台接口压根不该给商家访问

也就是说:

merchant_id 只是数据隔离的基础字段,不是完整权限模型。

3.4 接口和前端路由共用,越写越乱

比如:

  • 平台订单列表和商家订单列表共用一个接口
  • 通过 if/else 判断当前登录人是不是商家

一开始还行,后面随着:

  • 平台筛选项越来越多
  • 商家筛选项越来越多
  • 平台能看成本、商家不能看

接口就会越来越臃肿。


四、原理分析

平台后台和商家后台权限隔离真正要解决的,不是“多一个字段”这么简单,而是:

把账号边界、菜单边界、角色边界、接口边界、数据边界全部分清楚。

4.1 为什么平台后台和商家后台本质不同?

因为两者的控制视角不同。

平台后台是:

  • 全局视角
  • 管平台规则
  • 管商家
  • 管全站订单和结算

商家后台是:

  • 租户视角
  • 管自己店铺
  • 管自己商品
  • 管自己订单、库存、售后

这意味着两者天然就有不同的:

  • 菜单树
  • 角色体系
  • 数据范围
  • 接口权限

4.2 为什么“共用一套后台 + 加角色区分”往往不够?

因为这只能解决“功能显示”层面的问题,很难解决:

  • 路由和页面边界
  • 数据模型差异
  • 查询条件差异
  • API 输出字段差异

比如平台订单页可能要看:

  • 平台补贴
  • 商家结算金额
  • 风控标记

而商家订单页更关心:

  • 自己店铺订单状态
  • 发货状态
  • 售后状态

这两者即使页面名字都叫“订单列表”,本质上也不完全是一个系统。

4.3 最推荐的隔离思路是什么?

我更推荐这套:

账号体系分域,菜单树分域,角色分域,接口分域,数据按租户隔离。

也就是:

  • 平台账号和商家账号逻辑隔离
  • 平台菜单和商家菜单逻辑隔离
  • 平台角色和商家角色逻辑隔离
  • 平台接口和商家接口尽量分组
  • 商家数据天然带 merchant_id

这套思路比“全共用再打补丁”稳定得多。


五、数据库怎么设计更合理

如果你要做平台型电商,我建议数据库至少这样设计。

5.1 用户表增加账号域

可以在用户表增加一个字段:

  • account_type

常见值:

  • PLATFORM
  • MERCHANT

例如 sys_user

字段 说明
id 用户 ID
username 登录账号
password 密码
account_type 账号类型
merchant_id 商家 ID,平台账号可为空
status 状态

这样最基础的身份边界就有了。

5.2 角色表也要分域

sys_role 建议增加:

  • role_domain

常见值:

  • PLATFORM
  • MERCHANT

这样角色不会混。

例如:

  • 平台运营:PLATFORM
  • 商家运营:MERCHANT

虽然名字都叫运营,但边界完全不同。

5.3 权限资源表也建议分域

sys_permission 建议增加:

  • permission_domain

常见值:

  • PLATFORM
  • MERCHANT
  • COMMON

例如:

  • 商家审核:PLATFORM
  • 店铺装修:MERCHANT
  • 修改密码:COMMON

这样菜单树和按钮资源也能自然隔离。

5.4 业务表一定要带租户字段

商家侧核心业务表建议都带:

  • merchant_id

比如:

  • product
  • order_info
  • refund_order
  • coupon
  • warehouse

因为这是最基础的数据隔离条件。

如果是多店铺体系,还可以继续带:

  • shop_id

也就是:

  • 平台看全局
  • 商家默认按 merchant_id
  • 商家内部再按 shop_id 做细分

六、推荐的权限隔离方案

这里给一版更贴近线上落地的思路。

6.1 先分两个登录域

最清晰的做法通常是:

  • 平台后台登录入口
  • 商家后台登录入口

例如:

  • /platform/login
  • /merchant/login

这样做的好处是:

  • 登录态天然分域
  • 登录后加载的菜单树不同
  • 后端接口也更容易隔离

6.2 菜单树按域隔离

平台后台只返回平台菜单:

  • 商家管理
  • 商品审核
  • 平台结算
  • 风控管理

商家后台只返回商家菜单:

  • 我的商品
  • 我的订单
  • 我的售后
  • 店铺设置

也就是说:

不要让商家后台通过“隐藏菜单”的方式去隔离平台功能,最好从资源层就分开。

6.3 接口尽量分前缀

比如:

  • /api/platform/order/list
  • /api/merchant/order/list

这样做有几个明显好处:

  • 权限语义更清楚
  • Controller 更清晰
  • 不容易把平台逻辑和商家逻辑写乱
  • 审计和网关隔离更方便

6.4 数据权限判断规则要分层

我更建议你按这三层来判断:

平台账号
  • 是否有平台权限
  • 是否有指定商家/店铺的数据权限范围
商家账号
  • 是否属于某个 merchant_id
  • 是否有商家内部角色权限
  • 是否有店铺/仓库范围权限

也就是说,商家后台并不是“只看 merchant_id 就够了”,还可能继续细分。


七、前后端和 SQL 怎么配合

下面给一版比较贴近实际项目思路的示例。

7.1 登录后后端返回域信息

比如登录后返回:

{
  "userId": 1001,
  "accountType": "MERCHANT",
  "merchantId": 20001,
  "menus": [...],
  "perms": [...],
  "dataScopes": {
    "shopIds": [3001, 3002],
    "warehouseIds": [10]
  }
}

如果是平台后台账号:

{
  "userId": 1,
  "accountType": "PLATFORM",
  "merchantId": null,
  "menus": [...],
  "perms": [...],
  "dataScopes": {
    "merchantIds": [20001, 20002]
  }
}

这样前后端都知道自己当前处于哪个域。

7.2 商家订单列表 SQL 怎么做

商家后台查询订单列表时,后端应该天然带上:

  • 当前 merchant_id
  • 当前商家可见 shop_id

例如:

select id, order_no, shop_id, status, total_amount, create_time
from order_info
where merchant_id = #{currentMerchantId}
  and shop_id in (...)
order by create_time desc

这里的关键点是:

  • 商家永远不能通过前端传参决定 merchant_id
  • merchant_id 必须来自登录态

7.3 平台订单列表 SQL 怎么做

平台后台查询订单列表时,可能是:

  • 全量可见
  • 只看某些商家
  • 只看某些渠道

例如:

select id, order_no, merchant_id, shop_id, status, total_amount, create_time
from order_info
where 1 = 1
  and merchant_id in (...)
order by create_time desc

这时平台侧的数据权限更多体现为:

  • 平台角色范围
  • 平台岗位范围

而不是固定某一个商家。

7.4 商家详情接口也必须做租户校验

比如:

public OrderDetailDTO detail(Long orderId) {
    Order order = orderMapper.selectById(orderId);
    if (order == null) {
        return null;
    }

    LoginUser user = LoginUserHolder.get();
    if ("MERCHANT".equals(user.getAccountType())
            && !Objects.equals(order.getMerchantId(), user.getMerchantId())) {
        throw new RuntimeException("无权查看该订单");
    }

    return buildDetail(order);
}

这个校验特别关键,因为很多系统列表做了租户过滤,但详情接口忘了做。

7.5 平台和商家尽量不要共用完全相同的 DTO

因为两边关心的字段经常不同。

比如平台订单 DTO 可能包含:

  • 商家名称
  • 平台补贴
  • 结算状态
  • 风控标签

而商家订单 DTO 可能更关心:

  • 发货状态
  • 售后状态
  • 店铺内订单备注

所以如果强行共用,很容易出现:

  • 字段越堆越多
  • 权限判断越来越乱

八、为什么很多项目的平台和商家权限最后会做崩?

这也是线上项目非常常见的情况。

8.1 账号体系不分域

平台账号和商家账号混在一张逻辑里,没有明确域边界,后面权限会越来越难维护。

8.2 菜单资源不分域

一棵菜单树全靠“有没有权限”控制显示,结果资源树越来越大,配置越来越难。

8.3 角色名字相同,但语义完全不同

比如都叫“运营”,但平台运营和商家运营根本不是同一个角色模型。

8.4 所有接口都想共用

短期看起来省事,长期几乎一定会越来越乱。

8.5 只靠 merchant_id 拦数据,不做资源隔离

这样虽然能拦住一部分数据越权,但平台功能和商家功能仍然会混在一起。

8.6 平台管理员直接绕过一切规则,没有审计

平台管理员权限通常很高,但这不代表可以没有:

  • 审计日志
  • 操作留痕
  • 敏感操作二次确认

尤其是:

  • 结算
  • 改价
  • 风控处罚
  • 人工退款

这些动作风险很高。


九、压测与监控怎么写,文章才更像做过项目的人写的?

平台后台和商家后台权限隔离这类文章,如果只讲模型,不讲接口边界和排查视角,很容易显得太抽象。

所以建议补上观测和治理视角。

9.1 典型检查项示例

如果你要验证这套隔离是否靠谱,至少应该检查:

  • 商家账号是否能访问平台接口
  • 平台账号是否误入商家菜单
  • 商家导出接口是否只能导出自己数据
  • 详情接口是否校验 merchant_id
  • 列表、详情、导出、统计是否使用同一套租户过滤规则

9.2 线上建议重点监控哪些指标?

至少建议监控这些内容:

  • 平台接口被商家账号访问的拦截次数
  • 商家接口被平台账号误调的次数
  • 越权访问告警次数
  • 导出接口的租户审计日志
  • 敏感操作审计日志
  • 平台管理员高风险操作留痕

这些指标一旦写进文章里,会明显更像真实线上经验总结。


十、面试中怎么回答这个问题?

如果面试官问你:

平台后台和商家后台权限一般怎么隔离?

你可以这样回答。

10.1 回答思路

第一,平台后台和商家后台虽然都是后台系统,但它们的控制视角完全不同。平台后台管理的是全局资源和平台规则,商家后台管理的是某个租户自己的业务,所以两者本质上不应该只靠一套角色配置去硬区分。

第二,我通常会先把账号体系分域,比如区分 PLATFORMMERCHANT 两种账号类型。角色、菜单资源、接口资源也都会按域隔离,避免平台和商家资源混在同一棵权限树里。

第三,在数据层面,商家侧核心业务表都会带 merchant_id,商家账号查询时后端必须根据登录态自动带上 merchant_id 过滤,而不是信任前端传参。平台侧则根据平台角色的数据范围决定是否看全部商家还是部分商家。

第四,接口层我会尽量把平台和商家接口分前缀,比如 /platform/**/merchant/**,这样权限校验、网关控制、审计和代码维护都会更清晰。

第五,即使做了租户隔离,详情、导出、统计、敏感操作接口也必须继续做同样的租户校验和审计留痕,不能只在列表查询里限制。

10.2 面试官更想听到什么?

面试官真正想听的,通常不是一句“加个 merchant_id”,而是你有没有这些意识:

  • 你知道平台和商家是两种不同的权限域
  • 你知道账号、角色、菜单、接口都应该分域
  • 你知道 merchant_id 只是数据隔离基础,不是完整权限模型
  • 你知道列表、详情、导出、统计都必须统一隔离
  • 你知道平台高权限用户也需要审计留痕

如果你能把这些点讲清楚,面试官会明显觉得你做过真实电商后台,而不只是知道租户隔离这个词。


十一、总结

平台后台和商家后台权限隔离,真正难的不是“多加几个判断”,而是如何把:

  • 账号域
  • 角色域
  • 菜单域
  • 接口域
  • 数据域

真正从一开始就拆清楚。

如果只记一句结论,我觉得可以记住这句:

平台后台和商家后台最稳的做法,不是共用一套后台再靠权限硬拦,而是账号分域、角色分域、菜单分域、接口分域,数据再按租户自然隔离。

这套思路不一定最省代码,但通常更接近真实平台型电商系统的做法,也更容易长期维护。


十二、后续可以继续展开的内容

如果这篇你觉得还可以,后面这个系列我还可以继续写:

  • 电商后台的订单状态机怎么设计?
  • 平台审核流和商家操作流怎么拆?
  • 电商系统的店铺、仓库、类目权限怎么统一抽象?
  • 商家后台的菜单动态路由怎么设计?
  • 平台型电商的审计日志怎么做?

十三、结尾

如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注。
后面我会继续整理一些更偏实战的 Java 后端和电商系统设计文章。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐