目录
一、成果概述
这段时间实现了2种改密码方式:
- 邮箱改密码(原密码遗忘)
- 用户更换密码(原密码已知)
其中邮箱改密码功能需要打开redis使用。
二、方法1实现思路
1.发送邮件
yml配置文件:
spring:
mail:
host: smtp.qq.com
username: 280225*****@qq.com #邮箱
password: *********** #授权码
protocol: smtp
default-encoding: UTF-8
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
ssl:
enable: true
后端发送邮件:
@Value("${spring.mail.username}")//通过@Value注解读取 application-email 的username字段(也就是自己的邮箱)
private String from;
/**
* 发送简单的邮箱
*
* @param to 收件人
* @param theme 标题
* @param content 正文内容
* @param cc 抄送
*/
public void sendSimpleMail(String to, String theme, String content, String... cc) {
// 创建邮件对象
SimpleMailMessage message = new SimpleMailMessage();
try {
message.setFrom(String.valueOf(new InternetAddress(from, "心灵导航系统", "UTF-8"))); // 发件人
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
message.setTo(to); // 收件人
message.setSubject(theme); // 标题
message.setText(content); // 内容
if (ArrayUtils.isNotEmpty(cc)) {
message.setCc(cc);
}
// 发送
javaMailSender.send(message);
}
前端逻辑:
设计一个发送验证码按钮,倒计时60s,并在这期间将按钮设为禁用状态;
先获取请求权限,再获取邮箱验证码(具体逻辑已在后端实现),同时给出前端提示信息:
// 获取验证码
sendEmailCode() {
this.$refs.findPasswordForm.validateField('email', (valid) => {
if(valid) {
// 按钮倒计时
this.disabled = true;
this.msg = this.count-- + 's后重新获取';
this.timer = setInterval(() => {
this.msg = this.count-- + 's后重新获取';
if (this.count < 0) {
this.msg = '点击获取验证码';
this.count = 60;
this.disabled = false;
clearInterval(this.timer);
}
}, 1000);
// 发送验证码请求
common.getRequestCode(this.findPasswordForm.email).then(_ => {
common.getEmailCode(this.findPasswordForm.email, _.code).then(_ => {
if(_) {
// 通知邮箱发送
this.$notify({
title: '邮箱验证码已发送',
message: '验证码有效时长5分钟, 失效请重新发送',
type: 'success',
duration: 10 * 1000
})
}else {
this.$message({
type: "error",
message: "验证码发送失败,请重试"
})
}
})
})
}
});
},
前端dialogue:
2.更新密码
后端接口逻辑:
接受前端传来的数据,进行初步检验(邮箱格式、密码限制等):
String email = userPasswordDTO.getEmail();
String password = userPasswordDTO.getPassword();
String code = userPasswordDTO.getCode();
if (StringUtils.isAnyBlank(email, password, code)) {
// 非空
return Result.error(Constants.CODE_401,"参数为空");
}else if (!StringUtil.checkEmail(email)) {
// 邮箱格式校验
return Result.error(Constants.CODE_600,"邮箱格式错误");
}else if ( !StringUtil.checkPassword(password) ||code.length() != 6) {
// 密码格式和验证码长度校验
return Result.error(Constants.CODE_400,"参数错误");
}
return userService.findPassword(userPasswordDTO);//
然后根据获取的email查询数据库,看是否有这个用户;
若用户存在,则接着进行验证码的比对(需用到redis),如果一致则更新数据库存储的密码。
// 获取参数
String email = userPasswordDTO.getEmail();
String password = userPasswordDTO.getPassword();
String code = userPasswordDTO.getCode();
// 构造查询条件对象
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.select("id"); //查找id这一列
wrapper.eq("email", email);//equal等于
wrapper.last("limit 1");//无视优化规则直接拼到sql最后,有sql注入的风险
// 查询用户,是否存在
User user = this.baseMapper.selectOne(wrapper);// ???
if (user == null) {
return Result.error(Constants.CODE_600,"用户不存在");
}
// 获取正确的验证码
String rightCode = redisTemplate.opsForValue().get(RedisConstant.EMAIL + email);
if (!code.equals(rightCode)) {
// 验证码比对
return Result.error(Constants.CODE_400,"验证码不一致");
}
// 删除验证码
redisTemplate.delete(RedisConstant.EMAIL + email);
// 修改密码
User user1 = new User();
user1.setId(user.getId());
user1.setPassword(SecureUtil.md5(password));
前端调用后端API:
// 请求
user.findPassword(this.findPasswordForm).then(res => {
if(res.code === '200') {
// 请求成功
this.$message({
message: '密码修改成功',
type: 'success'
})
三、方法2实现思路
1.前端router
<el-dropdown-menu>
<el-dropdown-item @click="stuortea">个人信息</el-dropdown-item>
<el-dropdown-item @click="$router.push('/password')">修改密码</el-dropdown-item>
<el-dropdown-item @click=quit>退出系统</el-dropdown-item>
</el-dropdown-menu>
效果:
鼠标悬停,出现下拉框,点击“修改密码”跳转到相关界面:
对应代码:
<el-card style="width: 40%; margin: 10px">
<el-form ref="form" :model="form" label-width="80px" :rules="rules">
<el-form-item label="原密码" prop="password">
<el-input v-model="form.password" show-password></el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="form.newPassword" show-password></el-input>
</el-form-item>
<el-form-item label="确认新密码" prop="confirmPass">
<el-input v-model="form.confirmPass" show-password></el-input>
</el-form-item>
</el-form>
2.后端API
@ApiOperation("用户在设置里更新密码")
@PostMapping("/updatePassword")
public Result updatePassword(@RequestBody UserPasswordDTO userPasswordDTO) {
String password = userPasswordDTO.getPassword();
String newPassword = userPasswordDTO.getNewPassword();
if (StrUtil.isBlank(password) ||StrUtil.isBlank(newPassword)) {
return Result.error(Constants.CODE_400, "参数错误,部分参数为空");
}
if ( !StringUtil.checkPassword(newPassword) ) {
// 密码格式校验
return Result.error(Constants.CODE_400,"密码格式为:长度为6-18,只有数字和字母且至少包含1个字母");
}
userPasswordDTO.setPassword(SecureUtil.md5(password));
userPasswordDTO.setNewPassword(SecureUtil.md5(newPassword));
userService.updatePassword(userPasswordDTO);
return Result.success();
}
先判断前端传参是否有空值,然后再进行新密码格式的校验。
3.sql语句
@Update("update user set password = #{newPassword} where username = #{username} and password = #{password}")
int updatePassword(UserPasswordDTO userPasswordDTO);
这里用username和md5加密后的密码查数据库,也就是说原密码正确时,即可修改为新密码。
4.前端Vue调用
changePass() {
this.$refs['form'].validate((valid) => {
if (valid) {
if (this.form.newPassword !== this.form.confirmPass) {
this.$message.error('2次输入新密码必须一致!')
return
}
let user = JSON.parse(sessionStorage.getItem("user"))
this.form.username = user.username
request.post("/user/updatePassword", this.form).then(res => {
if (res.code === '200') {
this.$message({
type: "success",
message: "密码修改成功"
})
sessionStorage.removeItem("user") //退出系统后清除缓存的user信息,不能通过路由访问数据了
sessionStorage.removeItem("type")
this.$router.push("/login") //登录成功之后进行页面的跳转,跳转到主页
} else {
this.$message({
type: "error",
message: "修改失败"
})
}
})
}
})
}