在整个实现过程中,我们采用了分层架构,将业务逻辑和数据访问分离,提高了代码的可维护性和可扩展性。同时,我们还使用了 DecodedJWT
对象来增强安全性,确保了令牌的有效性和安全性。最后,通过记录日志,我们能够对任何潜在的错误进行监控和快速响应。这一功能不仅为用户带来了便利,也加强了系统的安全防护措施。 -------接上篇博客
UserController.Java
方法说明
该方法接收一个 recoverUsers
的请求体,通过 get
方法得到请求体内容。判断请求体的值是否为空,为空直接返回信息,提交效率。在更新用户密码前会先去查找数据库是否存在用户名为 XX 的用户,如果存在则不执行 if
语句。调用查询用户名和邮箱的方法,与数据库的信息比对,如果返回值为 true 就表示比对成功,调用更新密码的 userService
的方法,通过 userService
去调用 UserDao
更新用户密码。
这次我们为UserController.Java添加一个忘记密码的方法.在更新用户密码的时候需要校验我们通过登录生成的Token是否过期等.
我们先从请求头,中去提取出Token信息,使用@RequestHeader("Authorization")形参Authorization表示我们的application.yml配置文件中的header请求头的key的键名保持一致.
没有携带令牌就直接返回提示缺少令牌.通过substring()方法提取Token,从第七个字符开始提取到的就是我们请求所携带的Token.当请求携带Token后我们就可以对Token做解析,调用JwtUtils的静态方法,isTokenExpired()用于校验Token是否过期,没过期就从请求体里面的EecoverUsers.class通过getXX()方法接收字段.判断字段是否都为null.为空返回请检查必填项是否完整.更新密码之前先从数据库中查找是都有该用户才能够进行更新密码,这个里调用userService里面的findUser方法,传入一个user对象.该方法返回一个布尔值.
由于我们的忘记密码逻辑是根据,用户名和邮箱确认是否是本人操作,调用userService类里面的findUserAndEmail()方法,进行查询返回值为布尔值,取反我们得到的布尔值.取反的话数据库中没有查询到用户和邮箱所匹配的信息会返回false,我们取反操作得到true,在做响应,反之返回true取反为false,就不会执行if代码块的代码,从而让程序继续向下执行.当条件都满足的时候我们去调用更新密码的方法.
/*
* 该方法接收一个recoverUsers的请求体,通过get方法得到请求体内容.
* 判断请求体的值是否为空,为空直接返回信息,提交效率
* 在更新用户密码钱会先去查找数据库是否存在用户名为XX的用户,
* 如果存在则不执行if语句.调用查询用户名和邮箱的方法,与数据库的信息比对,
* 如果返回值为true就表示比对成功,调用更新密码的userService的方法,
* 通过userService去调用UserDao更新用户密码.
* */
@PostMapping("/recover")
public ApiResponse recover(@RequestBody RecoverUsers recoverUsers,@RequestHeader("Authorization") String authorizationHeader) {
if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
apiResponse.setCode(HttpStatus.UNAUTHORIZED.value());
apiResponse.setSuccess(false);
apiResponse.setMessage("缺少或无效的授权令牌");
return apiResponse;
}
// 提取 token
String token = authorizationHeader.substring("Bearer ".length());
try {
// 解析 token 并获取用户信息
DecodedJWT claims = jwtUtils.getClaimByToken(token);
if (claims == null && jwtUtils.isTokenExpired(claims)) {
apiResponse.setCode(HttpStatus.UNAUTHORIZED.value());
apiResponse.setSuccess(false);
apiResponse.setMessage("令牌无效或已过期");
return apiResponse;
}
// token 校验通过,继续处理忘记密码的逻辑
String email = recoverUsers.getEmail();
String user = recoverUsers.getUser();
String newPassword = recoverUsers.getNewPassword();
if (email == null || user == null || newPassword == null) {
apiResponse.setCode(400);
apiResponse.setSuccess(false);
apiResponse.setMessage("请检查必填字段是否已填写.");
return apiResponse;
}
Users users = usersService.findUser(user);
if (users == null) {
apiResponse.setCode(200);
apiResponse.setSuccess(false);
apiResponse.setMessage("无该用户");
apiResponse.setData(null);
return apiResponse;
}
// 根据用户名和邮箱进行查询如果查询到数据库中有用户名和邮箱能够匹配返回true
boolean isUserAndEmail = usersService.findUserAndEmail(user, email);
if (!isUserAndEmail) {
apiResponse.setCode(200);
apiResponse.setSuccess(false);
apiResponse.setData(null);
apiResponse.setMessage("请检查您输入的用户名及邮箱是否正确.");
return apiResponse;
}
// 当条件都满足的时候我们去携带用户想要跟新的密码进行修改密码操作
usersService.upDateUserPassWord(user, newPassword);
apiResponse.setCode(200);
apiResponse.setSuccess(true);
apiResponse.setData(null);
apiResponse.setMessage("密码重置成功.");
return apiResponse;
} catch (Exception e) {
logger.info("用户忘记密码接口错误: "+ e.getMessage());
// token 解析失败或其它异常处理
apiResponse.setCode(HttpStatus.INTERNAL_SERVER_ERROR.value());
apiResponse.setSuccess(false);
apiResponse.setMessage("服务器内部错误");
return apiResponse;
}
}
UserService.Java
findUserAndEmail 方法
该方法用于查找数据库中根据用户提交的邮箱和用户进行查找,与数据库比对是否匹配。
upDateUserPassWord 方法
该方法用于更新用户传递的密码,调用 DAO 层的方法后进行更新。返回值为 boolean。
UserController中的属性userService调用本类的方法,通过本类的属性userDao调用DAO层里面的sameEmailUsers将接收到的user与email在数据库中进行查询.upDatePassword()用户更新用户密码的方法.
/*
* 该方法用于查找数据库中根据用户提交的邮箱和用户进行查找,与数据库比对是否匹配
* */
public boolean findUserAndEmail(String user, String email) {
List<Users> users = userDao.sameEmailUsers(user, email);
// 该数组小于0表示没有查询到该用户携带的用户和email,不能进行密码重置
if (users.size() <= 0) {
return false;
}
return true;
}
* 该方法用于跟新用户传递的密码,调用DAO层的方法后进行更新.返回值为boolean
* */
public boolean upDateUserPassWord(String user, String passWord) {
boolean isUpDatePassword = userDao.upDatePassword(user, passWord);
if (isUpDatePassword) {
return true;
}
return false;
}
UserDao.Java
sameEmailUsers 方法
查询 user, email 是否相同。
upDatePassword 方法
根据用户希望更新的密码进行更新。
通过JdbcTemplate提供的query方法写SQL语句做查询,update()方法做更新.通过三元表达式判断查询到的userList是否为空,为空返回true,不为空返回false
Collections.emptyList()
返回一个不可变的空列表,这个列表是线程安全的,因为它不允许任何元素添加或删除。
- 如果
userList
是空的,返回一个不可变的空列表。- 如果
userList
不是空的,返回userList
本身。
/*
* 查询user,email是否相同
* */
public List<Users> sameEmailUsers(String user, String email) {
String sql = "SELECT user, email FROM users WHERE user = ? AND email = ?";
List<Users> userList = jdbcTemplate.query(sql, new Object[]{user, email}, new BeanPropertyRowMapper<>(Users.class));
return userList.isEmpty() ? Collections.emptyList() : userList;
}
/*
* 根据用户希望更新的密码进行跟新
* */
public boolean upDatePassword(String user, String password) {
String sql = "UPDATE users SET password = ? WHERE user = ?";
try {
jdbcTemplate.update(sql, password, user);
return true;
} catch (DataAccessException e) {
logger.info("更新密码时发生错误: " + e.getMessage());
return false;
}
}