瑞吉外卖中手机短信验证码登陆的问题以及过程整理
本篇接上一篇文章:
《基于SpringBoot+MybatisPlus开发的外卖管理项目》戳戳戳 http://t.csdn.cn/cRJYY
因为要实现真正的手机验证码登陆,需要上阿里云或者其他云购买相关的短信服务。
对于学习期的我们来说可能很难做到。
所以关于实现真实的发送短信验证的步骤,朋友们可以看视频跟着操作,这里就不再多说啦~
所以我们这里在需要发送短信时,使用Slf4j日志打印的方法,模拟手机收到短信。
再进行登陆验证即可。
在下载的资料中,发送短信这一项的前端代码和请求直接是去除了的,所以我们需要修改一下。
0、准备工作
-
放行资源添加上:在
LoginCheckFilter
中//找到我们之前的过滤器,添加两个路径即可。 // 2.1 定义不需要处理的请求 String[] urls = new String[]{ "/employee/login", //controller中的登陆请求 不拦截 "/employee/logout", //controller中的退出请求 不拦截 "/backend/**", //对静态资源进行放行,我们需要拦截的一般是对数据的请求 "/front/**", "/common/**",//测试上传下载时使用的路径 "/user/sendMsg", //发送验证码的请求的路径 "/user/login" //用户验证码登陆的路径 };
-
添加一个检测登陆的用户(user)的代码块,与之前员工(employee)登陆的写法一摸一样
//4.2 判断登陆状态,如果已登陆,则直接放行 if (request.getSession().getAttribute("user")!=null){ log.info("监测到已登陆,id为:{}",request.getSession().getAttribute("user")); //调用我们基于ThreadLocal的工具类,将用户id存储到线程中,方便在自动填充时取出用户id Long employeeId = (Long) request.getSession().getAttribute("user"); BaseContext.setCurrentId(employeeId); filterChain.doFilter(request,response); //放行 return; //若放行 后面代码无需执行 直接return }
1、修改代码
-
在
login.html
中的getCode方法
中,修改如下:getCode(){ this.form.code = '' const regex = /^(13[0-9]{9})|(15[0-9]{9})|(17[0-9]{9})|(18[0-9]{9})|(19[0-9]{9})$/; if (regex.test(this.form.phone)) { this.msgFlag = false //将前端随机生成验证码的代码注释 // this.form.code = (Math.random()*1000000).toFixed(0) //新增发送信息api的方法,并携带参数phone,注意时JSON格式的 sendMsgApi({phone:this.form.phone}) }else{ this.msgFlag = true } },
-
在
login.js
文件中添加:function sendMsgApi(data) { return $axios({ 'url': '/user/sendMsg', //请求路径 'method': 'post', //请求方式 data //请求携带的参数 }) }
-
还没结束,还有一个
login.html
中登陆的btnLogin
方法中有一个参数需要修改:按照下面的代码块修改之后,在跟着视频练习的时候,就会很顺畅;
同时也可以检查自己写的是否能够收到发验证码和登陆的请求。
btnLogin(){ if(this.form.phone && this.form.code){ this.loading = true //loginApi中的参数需要修改!这里只传了一个参数。 //const res = await loginApi({phone:this.form.phone}) //登陆页面需要两个参数phone和code,所以改成下面这样即可。 //否则,跟着视频写login请求时,自己无法测试。 const res = await loginApi(this.form) this.loading = false if(res.code === 1){ sessionStorage.setItem("userPhone",this.form.phone) window.requestAnimationFrame(()=>{ window.location.href= '/front/index.html' }) }else{ this.$notify({ type:'warning', message:res.msg}); } }
2、编写UserController
编写之前,我们需要导入,资料中带的utils包下的两个工具类:
一个是发送短信的API的工具类
SMSUtils
,一个是生成验证码的工具类ValidateCodeUtils
-
UserController中有的发送验证码和登陆方法:
@Slf4j //日志便于调试,在这里我们可以模拟收短信。 @RestController @RequestMapping("/user") //请求路径 public class UserController { @Autowired private UserService userService; //发送验证码 @PostMapping("/sendMsg") public R<String> sendMsg(@RequestBody User user, HttpSession session){...} //登陆 @PostMapping("/login") public R<User> sendMsg(@RequestBody Map map, HttpSession session){...}
-
发送验证码方法的具体内容
@PostMapping("/sendMsg") public R<String> sendMsg(@RequestBody User user, HttpSession session) { //获取用户手机号 String phone = user.getPhone(); if (phone != null){ //生成随机的4位验证码,使用工具类中的代码生成器 String code = ValidateCodeUtils.generateValidateCode(4).toString(); log.info("生成的验证码为:{}",code);//便于测试 //调用阿里云的短信服务API完成发送短信,按照api的格式去发送 //可以不删除,日后若是购买了短信服务,可以按照这个格式去发送即可 //SMSUtils.sendMessage("瑞吉外卖","templateCode",phone,code); //将生成的验证码保存到session中,方便之后登陆校验使用 session.setAttribute(phone,code); return R.success("短信发送成功..."); } return R.error("短信发送失败..."); }
-
处理登陆请求的方法
@PostMapping("/login") public R<User> login(@RequestBody Map map, HttpSession session) { //这里的参数使用Map //因为前端请求参数就是{"phone":"139...","code":"1234"} //使用Map接收更加便捷,当然使用UserDto接收也是可以的。 //获取手机号 String phone = map.get("phone").toString(); //获取验证码 String code = map.get("code").toString(); //从Session中获取之前保存的验证码 String codeInSession = session.getAttribute(phone).toString(); //进行验证码的比对,比对成功,登陆成功 if (codeInSession != null&& codeInSession.equals(code)){ //判断用户是否是新用户,是的话自动完成注册。 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getPhone,phone); User user = userService.getOne(queryWrapper); if (user==null){ user = new User(); //这里也可以加一句setStatus为1,看你数据库中的默认值是多少,一般注册了之后就是启用 user.setPhone(phone); userService.save(user);//将用户保存到数据库(自动注册) } session.setAttribute("user",user.getId()); return R.success(user); } return R.error("登录失败..."); }
测试通过!