NextJS应用忘记密码功能:临时令牌存储方案最优选择咨询
忘记密码令牌存储方案分析
两种现有方案的优劣对比
方案一:存入users表
- 问题点:
- 违背单一职责原则:users表是存储用户核心身份信息的核心表,临时的密码重置令牌不属于用户的永久属性,混存会让表的职责变得模糊。
- 存储冗余:多数用户的
forgotpass_token字段会是NULL,虽然现代数据库对NULL的存储有优化,但从设计优雅性来说不够合理。 - 核心表写压力:每次生成/清空令牌都要更新users表,增加了核心业务表的写操作频次,在高并发场景下可能影响核心业务的性能。
- 唯一优势:查询时无需联表,逻辑稍简单,但在现代数据库的联表性能下,这点优势可以忽略不计。
方案二:新建独立的forgotpass表
- 优势:
- 职责清晰:把临时的密码重置数据和用户核心数据分离,符合数据库设计的最佳实践。
- 无冗余存储:只有需要重置密码的用户才会生成记录,不会出现大量NULL值。
- 不影响核心表:所有令牌相关的写操作都在小表中进行,不会占用核心users表的资源。
- 扩展性强:后续如果需要添加令牌过期时间、使用状态等字段,直接扩展该表即可,无需改动核心表结构。
- 小缺点:验证令牌时需要联表查询,但这个开销极小,完全在可接受范围内。
更优的改进方案
在方案二的基础上,扩展表结构,增加安全相关的字段,提升密码重置流程的安全性和可维护性,建议的表结构如下:
user_id -- 外键关联users表的user_id forgotpass_token -- 唯一索引,确保令牌唯一 expires_at DATETIME -- 令牌过期时间,必须设置,防止长期有效 is_used BOOLEAN DEFAULT FALSE -- 标记令牌是否已使用,避免重复利用 created_at DATETIME DEFAULT CURRENT_TIMESTAMP -- 记录令牌生成时间,用于排查问题
为什么要加这些字段:
expires_at:密码重置令牌属于临时凭证,必须设置合理的过期时间(比如15分钟),防止令牌泄露后被长期滥用。验证时先检查令牌是否过期。is_used:令牌只能使用一次,用户完成密码重置后,立即将该字段标记为true,避免同一个令牌被多次使用。created_at:方便后续排查问题,比如统计令牌生成的频次、定位异常请求等。
总结
优先选择扩展后的独立forgotpass表方案,它在设计合理性、安全性、扩展性上都远优于存入users表的方案,是密码重置功能的标准存储方式。
内容的提问来源于stack exchange,提问作者Thunderbolt
相关产品推荐
相关产品推荐

