4. 密码迁移数据模型:源系统与目标系统的字段映射关系

做密码迁移审计,最核心的一块就是字段映射。说白了,就是把老系统里的密码相关字段,搬到新系统里。很多人觉得这很简单,不就是把数据复制过去吗?还真不是。

我遇到过好几家客户,迁移完成后才发现用户无法登录。查到最后,就是字段映射出了问题。源系统存的密码哈希是新格式,可目标系统还在用旧格式校验。这一错,几十万用户全得重置密码。今天我们就聊聊怎么避开这些坑。

4.1 字段映射为什么会这么重要?

字段映射,其实就是密码数据的翻译官。源系统和目标系统的数据结构很可能完全不同。

  • 字段名称可能不同——老系统叫password_hash,新系统叫passwd_digest
  • 字段类型可能不同——字符串长度、二进制字段、或者JSON对象
  • 字段格式可能不同——有的系统用Base64编码,有的用Hex
  • 字段约束可能不同——是否可为空、是否唯一、默认值是什么

你想想看,一个字段映射错了,轻则用户登录失败,重则整个密码策略失效,审计检查肯定过不了。

4.2 核心字段映射对照表

我整理了一份典型的字段映射表格。你可以用它作为参考,再结合自己系统的实际情况来调整。

源系统字段 目标系统字段 数据类型 约束条件 映射示例
user_pwd password_hash VARCHAR(256)→ VARCHAR(512) 非空,原定长→新变长 5d41402abc4b2a76b9719d911017c592(MD5→bcrypt)
pwd_salt salt_value VARCHAR(32)→ VARCHAR(64) 非空,默认值需转换 null→$2a$10$…(内嵌salt)
last_pwd_change password_last_updated_at DATETIME→ TIMESTAMP 时区转换,UTC统一 2023-06-15 14:30:00 CST→2023-06-15 06:30:00Z
pwd_expire_days password_expiration_days INT→ SMALLINT 范围检查,不可超出目标上限 999→365(强制上限)
pwd_version hash_algorithm_ver VARCHAR(10)→ VARCHAR(20) 枚举值映射,旧→新版本号 v1→SHA-256,v2→bcrypt_10
account_status password_reset_required INT(0/1)→ BOOLEAN 逻辑转换,1→true,0→false 1→true
我踩过的坑: 源系统的pwd_salt字段允许空值,而目标系统非空且有默认值。迁移后,所有原空salt记录被自动填了默认salt。用户登录时,新系统拿默认salt去验证旧哈希,结果永远不匹配。后来我们用COALESCE配合CASE WHEN做了特殊处理,才彻底解决。

4.3 字段映射的三种策略

实际项目里,字段映射不是什么复杂理论,但策略选错了就很麻烦。我个人习惯把这三种策略都先列出来,然后对照着选。

  1. 直接映射——最省事。字段名称和数据类型基本一致,直接复制。比如username到username。
  2. 值转换映射——最常见。字段名或格式不同,需要做个中间转换。比如account_status的1/0转成true/false。
  3. 复合映射——最复杂。多个源字段合并成一个目标字段。比如pwd_hash + pwd_salt 合并成 password_digest。
实用建议: 我一般先做直接映射,这能快速验证数据通道通不通。然后再处理值转换映射,这类映射容易出错但逻辑简单。复合映射我放到最后,因为涉及多个字段的联调,需要更细致的测试脚本。

4.4 映射过程中的数据类型检查

数据类型这块,很容易被忽略。我曾经见过一个项目,源系统密码字段是CHAR(60),目标系统是VARCHAR(255)。看起来没问题,但源系统里存的其实是256位的哈希,被截断到60位后。迁移过去,密码直接废了。

所以,我建议你在映射前先做三件事:

  • 长度检查——源数据的实际最大长度,是否超过目标字段的最大长度
  • 编码格式检查——源数据是Base64还是Hex,目标系统能否正常解码
  • 取值范围检查——比如源系统的pwd_expire_days最大999,目标系统只接受0-365,要做范围限缩
一个小技巧: 在迁移脚本里多加一条LENGTH()检查。一旦发现长度超限,立刻输出警告日志。这样你可以在批量迁移前就发现问题,而不是等迁移完才发现。

4.5 映射关系文档化

字段映射不能只靠脑子记,得写下来。我一般用一份YAML或JSON文件作为权威映射定义。审计检查时,直接拿这份文件去对。


字段映射:
  password_hash:
    源字段: user_pwd
    目标字段: password_hash
    映射类型: 值转换
    转换规则: |
      CASE
        WHEN LENGTH(source.user_pwd) > 60 THEN bcrypt_convert(source.user_pwd)
        ELSE source.user_pwd
      END
    空值处理: 不允许空值,如有空源则设为默认bcrypt哈希
    验证规则: 目标字段哈希与源字段哈希校验一致性

你还可以把这份映射表直接作为自动化测试的输入。每次迁移前跑一遍,确认映射逻辑和预期一致。

4.6 本章核心逻辑图

下面这张图展示了我刚才讲的数据映射核心逻辑。你可以把它当作一个决策树:先映射字段名称,再检查类型和约束,然后确认数据来源是不是同一个用户,最后做值转换。

密码迁移字段映射核心流程 源系统用户表 user_pwd, pwd_salt, ... 字段映射引擎 名称映射 → 类型转换 目标系统用户表 password_hash, salt_value, ... 映射规则配置 审计日志记录 说明 1. 源系统字段经过字段映射引擎,进行名称和类型转换。 2. 映射规则配置决定了具体的转换逻辑,比如值映射、复合映射。 3. 所有映射过程都会写入审计日志,便于追查问题。

注意看,映射规则配置和审计日志是分开的。规则配置决定“怎么做”,而审计日志记录“做了什么”。这两者配合好了,迁移后的故障排查才更高效。

4.7 常见映射陷阱和应对方法

最后,我总结几个最常见的映射陷阱。这些都来自我自己的项目经历。

  • 陷阱一:忽略密码格式差异。源系统存的是明文哈希,目标系统存的是带算法标识的哈希。直接映射过去,登录时算法标识不匹配,全报错。解决方案:映射前加一个算法标识检测逻辑。
  • 陷阱二:时间字段时区不一致。源系统用的CST,目标系统用UTC。迁移后用户看到的上次修改时间完全不对。我一般建议统一转成UTC再存。
  • 陷阱三:未处理默认值。源系统允许空字段,目标系统不允许。迁移时没填默认值,直接报错中断。解决方案:在映射脚本里加上COALESCE处理。
  • 陷阱四:忽略字段约束检查。比如唯一约束、外键约束。我记得有一次迁移时,源系统没有唯一约束,目标系统有。结果迁移脚本里没做去重,跑进去几千条重复记录,整个密码表全乱了。
最后的建议: 字段映射不是复制粘贴。它是整个密码迁移中最需要仔细核对的一环。你要把源系统的数据模型吃透,目标系统的数据模型也要吃透。然后拿着映射表,一条一条对照着做。我每次迁移前,都会手动跑一条用户数据的全链路映射验证,确认无误后再批量执行。