营销平台账号体系架构设计
摘要:当手机号、微信和用户名同时存在时,账号系统最容易犯的错误,是把登录方式当成用户本身。本文以 Begin Marketing 为例,解释如何用“登录身份、主账户、业务归属”三层模型,让入口持续增加,用户数据依然稳定。

做一个手机号登录并不难。真正麻烦的是,系统后来又增加微信登录、用户名密码,甚至更多入口时,怎样确认登录后的还是同一个人。
假设一位用户先用手机号参与活动,后来通过微信进入小程序,又为管理后台设置了用户名。如果系统把手机号、微信 OpenID 和用户名分别当成用户,这个人就会被拆成三份数据。换手机号、解绑微信或合并账号时,产品、权益和历史记录都可能需要迁移。
所以,账号系统首先要解决的不是“支持多少种登录方式”,而是:无论入口怎么变,业务上都必须落到同一个稳定主体。
先记住一个模型:一人、多身份、一账户
Begin Marketing 的设计可以浓缩成一句话:
登录身份回答“你如何证明自己”,主账户回答“你是谁、拥有什么”。
手机号、微信和用户名只是不同的“钥匙”。它们可以新增、替换或解绑,但钥匙后面应该始终是同一个主账户。营销产品、权益、等级和分析数据都归属于主账户,而不是某一把钥匙。
三层分工,让变化停在认证系统内

这套模型包含三个层次:
| 层次 | 负责什么 | 核心数据 |
|---|---|---|
| 登录身份 | 证明用户以哪种方式登录 | 手机号、微信、用户名等身份映射 |
| 主账户 | 表示唯一、稳定的业务主体 | user_code、账户状态、用户等级 |
| 业务归属 | 记录用户拥有的数据和权益 | 产品所有者、权益归属、分析口径 |
其中,user_account 是主账户,user_login_identity 保存各种登录身份到 user_code 的映射。一个主账户可以绑定多个身份,但一个登录身份只能属于一个主账户。
这条边界一旦建立,手机号变化、微信解绑或新增登录方式,都只会影响认证层。业务表不需要跟着迁移,因为它们始终只认稳定的 user_code。
核心实体如何关联

阅读这张 ER 图时,重点关注三条关系:
user_account通过user_code与user_login_identity建立 1:N 关系。platform_user_account独立存在,不与普通用户共用账号类型。sys_auth_session和sys_login_log使用subject_type + subject_code记录业务主体,login_identity_code只保留认证来源。
各表的自增 id 只用于表内物理定位。跨表关系、会话上下文和业务归属统一使用不可变业务编码,避免数据库主键泄漏到领域模型。
一次登录,最终只产生一个业务主体
无论用户选择哪种入口,登录链路都可以归一成五步:
- 客户端明确提交登录类型,例如用户名密码、手机验证码或微信授权码。
- 认证适配器按对应方式完成密码、验证码或第三方授权校验。
- 系统找到登录身份,并解析出它所属的
user_code;首次登录则在同一事务中创建主账户和身份。 - 系统读取主账户的最新状态和等级,然后建立会话。
- 后续请求只把主体类型和
user_code交给业务层。
这里有一个容易混淆的点:会话和登录日志可以记录本次使用的 identity_code,用于异常登录追踪和定向撤销会话;但产品、订单和权益不能使用它判断所有权。
认证系统可以记住用户用了哪把钥匙,业务系统只需要知道钥匙打开的是哪个账户。
“能做什么”和“拥有什么”必须分开判断

账号登录成功,并不代表用户可以执行所有操作。Begin Marketing 把授权拆成两个问题:
- 能力判断:当前等级是否允许创建新营销产品。
- 所有权判断:当前产品的
owner_user_code是否等于登录用户的user_code。
例如,用户等级从 1 降到 0 后,可以被禁止创建新产品,但他仍然拥有以前创建的产品。等级决定能力,所有者编码决定归属,两者不能互相替代。
同理,账户状态和等级这类会变化的信息,不适合长期固化在 JWT 中。请求到达时从服务端读取可信的最新状态,才能让禁用和降级及时生效。这样会增加一次状态读取,但换来的是更清晰的一致性边界。
平台管理员要走另一条账号链路
普通用户和平台管理员虽然都需要登录,但两者的信任边界完全不同。
平台管理员能够管理全局数据,由平台统一发放和停用;普通用户只能操作自己的业务数据,并通过手机、微信等入口自助注册。因此,Begin Marketing 使用独立的 platform_user_account 和平台认证入口,不与普通用户共用账户表、接口和权限语义。
分开设计并不是为了多建一张表,而是为了避免普通用户身份被错误提升为平台权限。
真正需要守住的是三条失败边界
主账户与登录身份拆分后,绑定、解绑和冲突处理必须有明确规则:
- 绑定前先证明身份。 新手机、微信或用户名只有在验证码、授权或原密码校验成功后才能绑定。
- 冲突时不自动合并。 如果一个身份已经属于其他主账户,系统应拒绝绑定;账户合并需要用户同时证明两个账户,不能静默迁移产品和权益。
- 解绑不能切断最后入口。 系统不能解绑最后一个可用身份;解绑某个身份后,还应撤销由它建立的活动会话。
账户被禁用时,应撤销该 user_code 的全部活动会话。日志也不能记录手机号、OpenID、密码、验证码或 Token 原文。
表结构拆分本身并不等于安全。可查询的登录标识需要使用摘要值,必须回显的敏感字段使用加密存储,密码则使用不可逆的自适应哈希;密钥轮换、验证码限流和会话撤销仍需要独立的安全机制。
这套设计有成本,也有适用范围
“主账户 + 多登录身份”会让登录过程多一次身份到主账户的查询,也会增加身份绑定、账户冲突和密钥管理的实现成本。
它适合同时存在 H5、小程序、公众号、手机号等入口,并且需要长期管理产品和权益的系统。对于永远只有单一用户名登录的内部工具,这种拆分可能偏重。
它也不是完整的身份与访问管理方案。企业组织、多门店、多租户协作仍需要独立的成员、角色和数据权限模型;金融、医疗等强合规场景还需要多因素认证、风险识别、设备信任和更完整的审计能力。
总结:让登录方式变化,让业务主体稳定
一个可演进的账号系统,关键不在于把所有登录方式塞进一张用户表,而在于守住四条原则:
- 平台管理员与普通用户保持独立的信任边界。
- 一个普通用户拥有一个主账户和多个登录身份。
- 会话可以记录认证来源,业务归属只能使用稳定的
user_code。 - 能力、所有权和登录身份分别判断,不能混成一个权限字段。
这样设计之后,增加邮箱、企业微信或 Passkey,只需要扩展身份类型和认证适配器;已有产品、权益和历史数据不必搬家。
登录方式会继续变化,但用户是谁、数据属于谁,应该始终保持稳定。
案例边界:本文根据 Begin Marketing 账号体系架构 V1.0 整理,重点解释多入口认证与稳定业务归属,不展开组织、租户、动态 RBAC 和完整 IAM 的实现。