重置密码
目录
重置密码流程概述
在用户需要重置密码之前,系统要求用户先绑定手机号。未绑定手机号的用户无法进行密码重置操作。整个重置密码的流程如下:
- 发送短信验证码:
- 调用
/sms/send
接口,向用户的手机发送短信验证码。
- 调用
- 绑定手机号:
- 调用
/user/bindPhone
接口,将用户的手机号与账号进行绑定。
- 调用
- 重置密码:
- 调用
/user/resetPassword
接口,使用短信验证码验证后,允许用户重置密码。
- 调用
API 接口详解
/sms/send 发送短信验证码
说明:发送短信验证码的具体实现参见 短信登录章节 。此处不再赘述。
/user/bindPhone 绑定手机号
功能:将用户的手机号与其账号进行绑定,以便后续的密码重置操作。
请求方式:POST
请求路径:/user/bindPhone
请求参数:
参数名 | 类型 | 必须 | 描述 |
---|---|---|---|
id | Long | 是 | 用户的唯一标识(用户 ID) |
code | Int | 是 | 短信验证码 |
phone | String | 是 | 用户的手机号 |
areaCode | String | 是 | 手机号的国家/地区码(如 86) |
codeType | Int | 是 | 验证码类型(绑定手机号为 1) |
示例请求数据:
{
"id": "439252701422661632",
"code": 265546,
"phone": "19957680449",
"areaCode": "86",
"codeType": 1
}
/user/resetPassword 重置密码
功能:在验证短信验证码后,允许用户重置其账户密码。
请求方式:POST
请求路径:/user/resetPassword
请求参数:
参数名 | 类型 | 必须 | 描述 |
---|---|---|---|
id | Long | 是 | 用户的唯一标识(用户 ID) |
code | Int | 是 | 短信验证码 |
phone | String | 是 | 用户的手机号 |
areaCode | String | 是 | 手机号的国家/地区码(如 86) |
codeType | Int | 是 | 验证码类型(重置密码为 1) |
newPassword | String | 是 | 用户的新密码(需符合密码策略) |
示例请求数据:
{
"id": "439257704450449408",
"code": 793131,
"phone": "19957680449",
"areaCode": "86",
"codeType": 1,
"newPassword": "123456"
}
实现细节
本节将详细介绍实现 /user/bindPhone
和 /user/resetPassword
接口的代码实现,包括控制层和业务层。
接口层实现
文件路径:com.enoleap.maliang.app.controller.UserController.java
package com.enoleap.maliang.app.controller;
import com.enoleap.maliang.app.model.PhoneLoginVo;
import com.enoleap.maliang.app.services.UserService;
import com.jfinal.kit.Kv;
import com.litongjava.annotation.Inject;
import com.litongjava.annotation.RequestPath;
import com.litongjava.model.body.RespBodyVo;
import cn.dev33.satoken.stp.StpUtil;
@RequestPath("/user")
public class UserController {
@Inject
private UserService userService;
/**
* 绑定手机号接口
* @param vo 包含绑定信息的 VO 对象
* @return 响应结果
*/
public RespBodyVo bindPhone(PhoneLoginVo vo) {
Object userId = StpUtil.getLoginId();
Long id = vo.getId();
Integer code = vo.getCode();
// 参数校验
if (id == null) {
return RespBodyVo.fail("用户ID不能为空");
}
if (code == null) {
return RespBodyVo.fail("验证码不能为空");
}
return userService.bindPhone(vo, userId);
}
/**
* 重置密码接口
* @param vo 包含重置信息的 VO 对象
* @return 响应结果
*/
public RespBodyVo resetPassword(PhoneLoginVo vo) {
Long id = vo.getId();
Integer code = vo.getCode();
// 参数校验
if (id == null) {
return RespBodyVo.fail("用户ID不能为空");
}
if (code == null) {
return RespBodyVo.fail("验证码不能为空");
}
return userService.resetPassword(vo);
}
}
说明:
@RequestPath("/user")
:标识此控制器处理以/user
开头的请求路径。bindPhone
方法:- 获取当前登录用户的
userId
。 - 校验必要参数是否存在。
- 调用业务层的
bindPhone
方法处理绑定逻辑。
- 获取当前登录用户的
resetPassword
方法:- 校验必要参数是否存在。
- 调用业务层的
resetPassword
方法处理密码重置逻辑。
业务层实现
文件路径:com.enoleap.maliang.app.services.UserService.java
package com.enoleap.maliang.app.services;
import com.enoleap.maliang.app.dao.SysUserInfoDao;
import com.enoleap.maliang.app.model.PhoneLoginVo;
import com.jfinal.kit.Kv;
import com.litongjava.db.activerecord.Db;
import com.litongjava.jfinal.aop.Aop;
import com.litongjava.model.body.RespBodyVo;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class UserService {
/**
* 绑定手机号
* @param vo 包含绑定信息的 VO 对象
* @param userId 当前用户的ID
* @return 响应结果
*/
public RespBodyVo bindPhone(PhoneLoginVo vo, Object userId) {
Long id = vo.getId();
Integer code = vo.getCode();
String areaCode = vo.getAreaCode();
String phone = vo.getPhone();
Integer codeType = vo.getCodeType();
// 验证短信验证码是否有效
if (code != null && !code.equals(440263)) { // 440263 可能为测试或默认验证码
String sql = "SELECT COUNT(1) FROM sys_sms_code WHERE id=? AND area_code=? AND phone=? AND code=? AND code_type=? AND TIMESTAMPDIFF(SECOND, create_time, NOW()) <= valid_seconds";
if (!Db.existsBySql(sql, id, areaCode, phone, code, codeType)) {
return RespBodyVo.fail("验证码无效或已过期。");
}
}
// 判断用户是否存在
if (userId == null) {
return RespBodyVo.fail("未找到用户,请先登录。手机号:" + phone);
}
SysUserInfoDao sysUserInfoDao = Aop.get(SysUserInfoDao.class);
// 更新用户的手机号
boolean ok = sysUserInfoDao.updatePhoneByUserId(userId, areaCode, phone);
if (ok) {
return RespBodyVo.ok("手机号绑定成功。");
} else {
return RespBodyVo.fail("手机号绑定失败,请稍后重试。");
}
}
/**
* 重置密码
* @param vo 包含重置信息的 VO 对象
* @return 响应结果
*/
public RespBodyVo resetPassword(PhoneLoginVo vo) {
Long id = vo.getId();
Integer code = vo.getCode();
String areaCode = vo.getAreaCode();
String phone = vo.getPhone();
Integer codeType = vo.getCodeType();
// 验证短信验证码是否有效
if (code != null && !code.equals(440263)) { // 440263 可能为测试或默认验证码
String sql = "SELECT COUNT(1) FROM sys_sms_code WHERE id=? AND area_code=? AND phone=? AND code=? AND code_type=? AND TIMESTAMPDIFF(SECOND, create_time, NOW()) <= valid_seconds";
if (!Db.existsBySql(sql, id, areaCode, phone, code, codeType)) {
return RespBodyVo.fail("验证码无效或已过期。");
}
}
// 查询用户是否存在
String sql = "SELECT id FROM sys_user_info WHERE area_code=? AND phone=? AND deleted=0";
Long userId = Db.queryLong(sql, areaCode, phone);
if (userId == null) {
return RespBodyVo.fail("未找到用户,请先注册。手机号:" + phone);
}
SysUserInfoDao sysUserInfoDao = Aop.get(SysUserInfoDao.class);
log.info("正在为用户重置密码:{}, {}", vo.getAreaCode(), vo.getPhone());
// 更新用户密码
boolean ok = sysUserInfoDao.updatePasswordById(userId, vo.getNewPassword());
if (ok) {
return RespBodyVo.ok("密码重置成功。");
} else {
return RespBodyVo.fail("密码重置失败,请稍后重试。");
}
}
}
说明:
bindPhone 方法:
- 验证短信验证码的有效性:
- 查询
sys_sms_code
表,确保验证码存在且未过期。 - 特殊验证码
440263
可能用于测试或跳过验证(视业务需求而定)。
- 查询
- 验证用户是否已登录(
userId
不为null
)。 - 调用
SysUserInfoDao
更新用户的手机号。
- 验证短信验证码的有效性:
resetPassword 方法:
- 验证短信验证码的有效性,与绑定手机号类似。
- 查询用户是否存在于
sys_user_info
表中。 - 调用
SysUserInfoDao
更新用户的密码。
日志记录:
- 在重置密码过程中,记录相关操作日志,便于后续审计和问题排查。
注意事项与最佳实践
安全性:
- 验证码验证:确保验证码的生成和验证过程安全,防止暴力破解和重放攻击。
- 密码策略:新密码应符合安全策略,如最小长度、包含字母和数字等,防止弱密码。
- 数据传输:所有敏感数据(如验证码、新密码)应通过 HTTPS 进行传输,确保数据在传输过程中不被窃取。
- 错误信息:避免泄露过多错误信息,尤其是与安全相关的详细信息,以防信息泄露。
验证码管理:
- 有效期:验证码应有明确的有效期(如 5 分钟),超过有效期后自动失效。
- 验证码类型:使用
codeType
参数区分不同场景下的验证码,避免混淆。 - 频率限制:限制用户请求验证码的频率,防止短信轰炸和滥用。
日志记录:
- 记录关键操作日志,如验证码发送、绑定手机号、密码重置等,便于后续审计和问题排查。
- 注意日志中不应记录敏感信息,如密码明文。
用户体验:
- 提示信息:提供清晰、友好的提示信息,引导用户完成操作。
- 错误处理:在验证码失效或输入错误时,给予明确的错误提示,并引导用户重新获取验证码。
- 输入校验:前端应对用户输入进行初步校验,如手机号格式、密码强度等,提升用户体验并减少服务器压力。
数据一致性:
- 在绑定手机号和重置密码过程中,确保数据库操作的原子性,避免数据不一致的情况发生。
依赖管理:
- 确保相关依赖(如
SysUserInfoDao
、Db
)的正确配置和初始化,避免运行时错误。
- 确保相关依赖(如
结语
通过本指南,您可以实现用户密码重置功能,包括发送短信验证码、绑定手机号以及重置密码的完整流程。确保在实际应用中遵循安全性和用户体验的最佳实践,以提升系统的安全性和用户满意度。如在实现过程中遇到问题,建议参考相关技术文档或在技术社区寻求帮助。