做电商网站,用户把密码忘了是再常见不过的事。登录页那个“忘记密码”的链接,看着不起眼,真做起来却有不少细节。今天就聊聊这个功能在JavaWeb项目里到底怎么落地。
先说整体思路。用户点“忘记密码”后,流程一般是:填账号→验证身份→重置密码→重新登录。身份验证的方式主流有两种,一种是邮箱收验证码,一种是手机收短信。考虑到电商平台手机号基本都绑定了,用手机验证码更普遍,但邮箱作为备用通道也值得保留。后端逻辑上,核心就是生成一个有时效性的凭证或验证码,校验通过后允许修改密码。
具体到步骤。第一步,用户输入注册时的用户名或手机号。这里别急着下一步,先查一下这个账号存不存在。如果不存在,直接提示“账号未注册”,别让用户傻等。存在的话,进入发送验证码环节。
验证码这块,强烈建议用6位纯数字,别用复杂字符,用户要手输的,越简单越好。生成后存到哪儿?存数据库临时表,或者干脆放Redis,给它设5分钟有效期。存数据库的话,表结构可以很简单:id、user_id、code、expire_time、create_time。存Redis的话,key用“forgot:userId”这种格式,value就是验证码,setex(300)就行,省事还自动过期。用Java的UUID或者Random类都能生成,记得用SecureRandom更安全。
发送验证码时,如果集成了阿里云短信或者腾讯云短信,调一下API就行。这里要提醒一下,接口得加个频率限制,同一个手机号一分钟内别重复发送,不然用户手一抖点三下,短信费划不来,体验也差。

用户收到验证码,填进去提交时,后端要做的校验就几个:验证码对不对、过期没、是哪个用户的。比对的时候别用数据库里的明文存验证码,至少加个盐哈希一下。Redis的话就简单,直接get出来跟用户提交的equals比对,但要注意用constantTimeEquals这类防时间攻击的方法,虽然电商场景风险不算高,习惯养好没坏处。
校验通过后,跳到设置新密码的页面。这里有个细节容易被忽略:改密码的接口一定要再带一个临时凭证,比如一个token,不能只靠验证码。因为验证码已经被用户用过了,如果校验完就直接放行改密码,存在CSRF风险。做法是校验验证码通过后,生成一个一次性token(UUID就行),存Redis或数据库,有效期10分钟,跳到新密码页面把这个token带上。修改密码时校验token,用一次就删掉,防止重放攻击。
新密码本身要过一遍强度校验,长度至少6位,最好强制数字+字母组合。存的时候用BCrypt加盐哈希,千万别用MD5或者SHA1裸存,现在破MD5太容易了,一堆彩虹表。Spring Security自带的BCryptPasswordEncoder就能直接用,几行代码的事。
改完密码,记得把该用户所有登录会话失效。这步很多人会漏。简单做法是清除该用户相关的token或session,如果用了Spring Session或者JWT,得把对应的存储删掉,否则用户旧密码的登录态还活着,那改密码就没意义了。
还有一个细节,成功页面别直接跳回登录页就完事,可以加个“密码已重置,请用新密码登录”的提示,顺手把用户引到登录页。失败的情况得具体说,比如“验证码错误”“验证码已过期”,让用户清楚下一步干嘛。
数据这块,实际项目中验证码发送成功率在99%左右,如果低于这个数,先查短信服务商的签名和模板有没有过审。用户找回密码的转化率大概在60%到70%,流失的大多卡在验证码收不到或者等待时间太长,所以发送速度和到达率比花哨的功能更关键。
最后提一句安全。这种接口最容易被人恶意刷,短信接口要加图形验证码或者滑块,改密码接口要限流,按IP和用户维度都限制一下,比如每IP一小时10次。电商网站用户量大,被薅羊毛的盯上可不是小事。
整体下来,功能不复杂,但每个环节都要想到。从用户输入账号到登录成功,路径清晰,状态明确,异常有处理,这样就够了。