SpringBoot实现短信发送及手机验证码登录
一、短信发送
1.1 阿里云短信服务
也可以在下面这个地方查看短信服务
1.1.1 设置短信签名
短信签名就是短信发送者的署名,表示发送方的身份
1.1.2 模板管理
申请下来之后可以点击详情进行查看
其中模板CODE是自动生成的,不用管,重点是模板的内容
1.1.3 设置AccessKey
创建新的用户
勾选上之后,我们在编程代码中就能使用
当我们创建用户成功后,就生成了一对AccessKey,即AccessKey ID(用户名) 与AccessKey Secret(密码)
很多人在这里的时候不小心没截图或者没保存就关了,丢失了AccessKey,但是不要紧,还可以再次创建
还有就是如果别人知道了我们的AccessKey,那别人使用的时候会就花我们的钱。我们也可以把泄露的AccessKey禁用
之后再新增授权。这次授权的意思就是仅仅授予有关短信服务的,即是我们泄露了,别人也只能操作短信服务,对我们的影响很小。
1.2 短信发送——代码开发
参照官方文档即可
1.2.1 导入maven坐标
<dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.16</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <version>2.1.0</version> </dependency>
1.2.2 调用API
/** * 短信发送工具类 */ public class SMSUtils { /** * 发送短信 * @param signName 签名 * @param templateCode 模板 * @param phoneNumbers 手机号 * @param param 参数 */ public static void sendMessage(String signName, String templateCode,String phoneNumbers,String param){ DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", "LTAI5tHRxs2FeCu5JcJTGbm2", "v0H4PaJpXSwNr6XChtlVYAgmQWgKRA"); IAcsClient client = new DefaultAcsClient(profile); SendSmsRequest request = new SendSmsRequest(); request.setSysRegionId("cn-hangzhou"); // 要发送给那个人的电话号码 request.setPhoneNumbers(phoneNumbers); // 我们在阿里云设置的签名 request.setSignName(signName); // 我们在阿里云设置的模板 request.setTemplateCode(templateCode); // 在设置模板的时候有一个占位符 request.setTemplateParam("{\"code\":\""+param+"\"}"); // request.setPhoneNumbers("1368846****");//接收短信的手机号码 // request.setSignName("阿里云");//短信签名名称 // request.setTemplateCode("SMS_20933****");//短信模板CODE // request.setTemplateParam("张三");//短信模板变量对应的实际值 try { SendSmsResponse response = client.getAcsResponse(request); System.out.println("短信发送成功"); }catch (ClientException e) { e.printStackTrace(); } } }
1.3 手机验证码登录
- 方便、快捷、无需注册、直接登陆
- 使用短信验证码作为登录凭证,无序记忆密码
- 安全
登录流程: 输入手机号 -> 获取验证码 -> 输入验证码 -> 点击登录 -> 登陆成功
注意: 通过手机验证码登录,手机号是区分不同用户的标识
1.3.1 用户数据库表
因为是通过手机和验证码登录的,所以没有用户名和密码字段
1.3.2 修改过滤器
在写代码之前记得要在过滤器中定义不需要处理的请求路径/user/sendMsg和/user/login
然后访问路径: http://localhost:8080/front/page/login.html
/** * 检查用户是否已经完成登录 * 过滤器与拦截器的区别:Filter对所有访问进行增强(在Tomcat服务器进行配置),Interceptor仅针对SpringMVC的访问进行增强 */ @Slf4j @WebFilter(filterName = "loginCheckFilter", urlPatterns = "/*") //urlPatterns指定拦截哪些路径 public class LoginCheckFilter implements Filter { // 此对象的作用:路径匹配器, 匹配路径时支持通配符 public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // servletRequest向下强制类型转换 HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; //1. 获取本次请求的URI( URI:请求的资源路径) String requestURI = request.getRequestURI(); log.info("拦截到请求:{}", request.getRequestURI()); // 定义不用处理的请求路径 String[] urls = new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**", "/common/**", "/user/sendMsg", "/user/login" }; //2. 判断本次请求是否需要处理(因为有些请求并不需要用户登录) boolean check = check(requestURI, urls); //3.如果不需要处理,则直接放行 if (check) { log.info("本次请求{}不需要处理", request.getRequestURI()); filterChain.doFilter(request, response); return; } //4-1.判断登录状态,如果已登录,则直接放行.从session中获取用户,如果获取到说明已经登录 if (request.getSession().getAttribute("employee") != null) { log.info("用户已登录,用户id为{}", request.getSession().getAttribute("employee")); Long empId = (Long) request.getSession().getAttribute("employee"); BaseContext.setCurrentId(empId); filterChain.doFilter(request, response); return; } //4-2.判断登录状态,如果已登录,则直接放行.从session中获取用户,如果获取到说明已经登录 if (request.getSession().getAttribute("user") != null) { log.info("用户已登录,用户id为{}", request.getSession().getAttribute("user")); Long userId = (Long) request.getSession().getAttribute("user"); BaseContext.setCurrentId(userId); filterChain.doFilter(request, response); return; } //5.如果未登录则返回未登录结果 log.info("资源路径路径:{},用户未登录{}", request.getRequestURI(), request.getSession().getAttribute("employee")); // 通过输出流的方式向客户端响应数据 (为什么要返回这个NOTLOGIN? 因为前端需要这个来进行判定是否登录) response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN"))); // filterChain.doFilter(request, response); 加上这个就无法实现 } /** * 检查本次请求是否需要放行 * * @param requestURI 请求的资源路径 * @param urls 放过的路径 * @return true 放行 */ public boolean check(String requestURI, String[] urls) { for (String url : urls) { boolean match = PATH_MATCHER.match(url, requestURI); if (match) { // 放行 return true; } } return false; } }
1.3.3 随机生成验证码的工具类
/** * 随机生成验证码工具类 */ public class ValidateCodeUtils { /** * 随机生成验证码 * @param length 长度为4位或者6位 * @return */ public static Integer generateValidateCode(int length){ Integer code =null; // 长度为4 if(length == 4){ code = new Random().nextInt(9999);//生成随机数,最大为9999 if(code < 1000){ code = code + 1000;//保证随机数为4位数字 } // 长度为6 }else if(length == 6){ code = new Random().nextInt(999999);//生成随机数,最大为999999 if(code < 100000){ code = code + 100000;//保证随机数为6位数字 } // 其他情况 }else{ throw new RuntimeException("只能生成4位或6位数字验证码"); } return code; } /** * 随机生成指定长度字符串验证码 * @param length 长度 * @return */ public static String generateValidateCode4String(int length){ Random rdm = new Random(); String hash1 = Integer.toHexString(rdm.nextInt()); String capstr = hash1.substring(0, length); return capstr; } }
1.3.4 手机验证码登录-- 发送验证码
两次ajax请求:
1. 登录页面输入手机号,点击【获取验证码】按钮,页面发送ajax请求,在服务端调用短信服务API给指定手机号发送验证码短信
2. 在登录页面输入验证码,点击【登录】按钮,发送ajax请求,在服务端处理登录请求
@PostMapping("/sendMsg") public R<String> sendMsg(@RequestBody User user, HttpSession session){ // 1.获取手机号 String phone = user.getPhone(); if(StringUtils.isEmpty(phone)){ return R.error("短信发送失败"); } // 2.随机生成四位验证码 String code = ValidateCodeUtils.generateValidateCode(4).toString(); // 3.调用阿里云提供的短信服务 SMSUtils.sendMessage("张靖奇","",phone,code); // 4.需要将生成的验证码保存到session中 session.setAttribute(phone,code); return R.success("验证码短信发送成功"); }
1.3.5 手机验证码登录-- 验证验证码
// 其实传过来的phone:xxxx,code:xxx 也可以用map集合接收 @PostMapping("/login") public R<User> login(@RequestBody Map map, HttpSession session) { log.info(map.toString()); // 1. 获取手机号 String phone = map.get("phone").toString(); // 2. 获取验证码 String code = map.get("code").toString(); // 3. 从Session中获取保存的验证码 Object codeInSession = session.getAttribute(phone); // 4. 进行验证码比对(页面提交的验证码和Session中保存的验证码比对) if (codeInSession != null && codeInSession.equals(code)) { // 5.对比成功,说明登录成功 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getPhone,phone); User user = userService.getOne(queryWrapper); if (user==null){ // 6. 如果新用户,自动注册 user = new User(); user.setPhone(phone); user.setStatus(1); userService.save(user); } session.setAttribute("user",user.getId()); return R.success(user); } return R.error("登录失败"); }
到此这篇关于SpringBoot实现短信发送及手机验证码登录的文章就介绍到这了,更多相关SpringBoot 手机验证码登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
最新评论