快捷搜索:  汽车  科技

找回密码是怎么实现的(找回密码功能的实现)

找回密码是怎么实现的(找回密码功能的实现)reset () { var _this = this // name发送到后端,正确会返回其邮箱名称(后端进行了脱敏),否则提示name工号不存在 this.$axios.post('reset' {'name': this.name}) .then(function (res) { if (res.data.success) { // 已发送重置密码链接至xx邮箱,如果邮箱不能接收,请联系管理员! var msg = '重置链接已发送至' res.data.data '邮箱,如果邮箱不能接收,请联系管理员!' _this.$notify({ t

首先表明我这个项目是个小项目,不存在高并发,不存在微服务,使用人数是个位数的....(仅用来配合目前工作使用的(非IT行业,未入行))

技术栈:
  • 后端:springboot项目;
  • 前端:vue、elementUI。
思路:

由于项目比较小,也就不上redis了,直接使用mysql数据库,新建一个reset表 (字段:username、uuid)。

前端流程如下:

1.在登陆页中增加“找回密码”按钮:

找回密码是怎么实现的(找回密码功能的实现)(1)

2.点击后弹出:

找回密码是怎么实现的(找回密码功能的实现)(2)

3.输入“工号”后点确认:

a.工号不存在:然后整个流程结束

找回密码是怎么实现的(找回密码功能的实现)(3)

b.工号存在:由服务端进行相关操作后,返回数据(用户邮箱且进行脱敏处理)拼接显示。

找回密码是怎么实现的(找回密码功能的实现)(4)

前端的js代码如下:

reset () { var _this = this // name发送到后端,正确会返回其邮箱名称(后端进行了脱敏),否则提示name工号不存在 this.$axios.post('reset' {'name': this.name}) .then(function (res) { if (res.data.success) { // 已发送重置密码链接至xx邮箱,如果邮箱不能接收,请联系管理员! var msg = '重置链接已发送至' res.data.data '邮箱,如果邮箱不能接收,请联系管理员!' _this.$notify({ title: '密码重置' message: msg type: 'success' duration: 2000 }) _this.dialogVisible = false } else { //工号不存在时提示 _this.$notify.error({ title: '密码重置' message: '请检查工号输入是否正确' duration: 2000 }) } }) }后端发送邮件如下:

主要是reset这个api接口

uuid生成、邮箱名脱敏使用的是hutool工具。数据库框架使用的是mybatis-plus

@ResponseBody public Result<String> reset(@RequestBody Map<String String> map) { String username = map.get("name"); User user = userDao.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername username)); if (user != null) { String email = user.getEmail(); // 模拟化处理:邮箱名称脱敏 String emailto = DesensitizedUtil.email(email); // reset表中存储当前id和uuid随机字符串值 // 先查询表中是否有当前username是否存在,如果有则直接创建邮件,无则新建记录并创建邮件; Reset reset = resetMapper.selectOne(Wrappers.<Reset>lambdaQuery().eq(Reset::getUsername username)); if (reset == null) { resetMapper.insert(new Reset(username IdUtil.simpleUUID())); reset = resetMapper.selectOne(Wrappers.<Reset>lambdaQuery().eq(Reset::getUsername username)); } String uuid = reset.getUuid(); //发送邮件 MimeMessage mailMessage = null; try { mailMessage = javaMailSender.createMimeMessage(); //是否发送的邮件是富文本(附件,图片,html等) MimeMessageHelper helper = new MimeMessageHelper(mailMessage true); //发送者和接收者 helper.setFrom(from); helper.setTo(email); //邮件标题 helper.setSubject("yderp密码重置-工号:" username); //邮件内容拼接 helper.setText("<p>用户" username "你好:你正在进行密码重置,本链接仅当天一次有效,请点击以下按钮进行修改:</p>\n" "\t\t<a href=\"" myAddress "resetPassword?uuid=" uuid "\"" ">点击修改密码</a>" true); javaMailSender.send(mailMessage); }catch (Exception e) { return Result.failure(505 e.toString()); } return Result.defaultSuccess(emailto); } else { return Result.failure(506 "当前工号不存在"); } }重置密码链接页面:

需要对uuid进行判断,否则跳转到无权限页

@GetMapping("/resetPassword") public String resetPassword(String uuid){ if (uuid == null || "".equals(uuid)) { return "403"; } // 查询uuid是否有效 Reset one = resetMapper.selectOne(Wrappers.<Reset>lambdaQuery().eq(Reset::getUuid uuid)); if (one == null) { return "403"; } return "resetPassword"; }

重置密码使用的是后端模板页面:resetPassword.html

重点是:1.获取url中uuid参数的值、

2.对新密码进行正则校验、

3.修改密码请求需要将当前uuid值传递至后端进行校验。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>重置密码</title> <style> table { border-collapse: collapse; } [v-cloak]{ display: none !important; } </style> <script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.9.0/moment.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.9/vue.min.js"></script> <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0/axios.min.js"></script> <!-- 引入组件库 --> <script src="https://unpkg.com/element-ui/lib/index.js"></script> <!-- 引入样式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico"> <script> window.onload = function () { new Vue({ el:"#main" data: { uuid: "" password: '' } created() { this.uuid = this.GetQueryString("uuid") } methods:{ resetPassword() { var _this = this var match = /^[a-zA-Z]\w{7 11}$/ if (!match.test(this.password)) { _this.$message.error('新密码以字母开头 8-12位长度') } else { axios.post('upPassword' {password: _this.password uuid: _this.uuid}).then(function (res) { if(res.data.success === true) { _this.$message({ message: res.data.data type: 'success' }) }else { _this.$message.error(res.data.message) } }) } } // 查找url中参数的方法 GetQueryString(name) { var reg = new RegExp("(^|&)" name "=([^&]*)(&|$)"); var r = window.location.search.substr(1).match(reg); if (r != null) { return unescape(r[2]); } return null; } } }) } </script> </head> <body> <div id="main"> <div style="width: 200px;margin-top:10%;margin-left: 40%;"> <el-input v-model="password" placeholder="请输入新密码"></el-input> <div style="margin: 20px auto"> <el-button type="primary" @click="resetPassword">修改密码</el-button> </div> </div> </div> </body> </html>重置密码的后端api

1.需要对前端传过来的密码再次进行正则校验;

2.需要对uuid在reset表中进行查询,如果没有数据表明链接已失效;

3.修改密码中需要对密码进行加密存储;

4.修改成功后,删除reset表中相应的记录。

//修改密码 @PostMapping("/upPassword") @ResponseBody public Result<String> upPassword(@RequestBody Map<String String> map) { String uuid = map.get("uuid"); String password = map.get("password"); String match = "[a-zA-Z]\\w{7 11}"; // 密码正则验证 if (uuid == null || password == null || !password.matches(match)) { return Result.failure(501 "参数错误或密码不匹配!"); } // 查出uuid记录 Reset reset = resetMapper.selectOne(Wrappers.<Reset>lambdaQuery().eq(Reset::getUuid uuid)); if (reset == null) { return Result.failure(502 "当前链接已失效!"); } String username = reset.getUsername(); User user = userDao.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername username)); // 然后修改密码,并且删除Reset表中相应username记录,需要加密 user.setPassword(BCrypt.hashpw((password))); int i = userDao.updateById(user); if (i > 0) { resetMapper.delete(Wrappers.<Reset>lambdaQuery().eq(Reset::getUsername user.getUsername())); return Result.defaultSuccess("密码修改成功!"); } return Result.failure(503 "其他错误!"); }

至此,密码找回功能已经实现。当然上面的api接口均要被权限控制框架所放行。

但是还有一个问题,我们在邮箱中设置显示的是链接当天一次有效,如果当天没有打开,或者当天没有修改,在第二天依然会有效,需要的是在凌晨0点进行清除reset表的操作,需要的是一个定时任务。新建一个定时配置类:

@Configuration //1.主标记配置类 @EnableScheduling // 2.开启定时任务 public class ScheduleTask { private ResetMapper resetMapper; public ScheduleTask(ResetMapper resetMapper) { this.resetMapper = resetMapper; } //3.添加定时任务 每天0点执行清空表 @Scheduled(cron = "0 0 0 * * ?") private void clearReset() { //清除reset表中数据 resetMapper.clearAll(); } } @Mapper @Component public interface ResetMapper extends BaseMapper<Reset> { @Update("truncate table reset") void clearAll(); }

纯自学野路子来的,不要喷我,可能逻辑上或者写的格式不好看,关键是能跑得起来。

猜您喜欢: