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 字段映射的三种策略
实际项目里,字段映射不是什么复杂理论,但策略选错了就很麻烦。我个人习惯把这三种策略都先列出来,然后对照着选。
-
直接映射——最省事。字段名称和数据类型基本一致,直接复制。比如
username到username。 -
值转换映射——最常见。字段名或格式不同,需要做个中间转换。比如
account_status的1/0转成true/false。 -
复合映射——最复杂。多个源字段合并成一个目标字段。比如
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 本章核心逻辑图
下面这张图展示了我刚才讲的数据映射核心逻辑。你可以把它当作一个决策树:先映射字段名称,再检查类型和约束,然后确认数据来源是不是同一个用户,最后做值转换。
注意看,映射规则配置和审计日志是分开的。规则配置决定“怎么做”,而审计日志记录“做了什么”。这两者配合好了,迁移后的故障排查才更高效。
4.7 常见映射陷阱和应对方法
最后,我总结几个最常见的映射陷阱。这些都来自我自己的项目经历。
- 陷阱一:忽略密码格式差异。源系统存的是明文哈希,目标系统存的是带算法标识的哈希。直接映射过去,登录时算法标识不匹配,全报错。解决方案:映射前加一个算法标识检测逻辑。
- 陷阱二:时间字段时区不一致。源系统用的CST,目标系统用UTC。迁移后用户看到的上次修改时间完全不对。我一般建议统一转成UTC再存。
- 陷阱三:未处理默认值。源系统允许空字段,目标系统不允许。迁移时没填默认值,直接报错中断。解决方案:在映射脚本里加上
COALESCE处理。 - 陷阱四:忽略字段约束检查。比如唯一约束、外键约束。我记得有一次迁移时,源系统没有唯一约束,目标系统有。结果迁移脚本里没做去重,跑进去几千条重复记录,整个密码表全乱了。