SpringBoot——短信发送、手机验证码登录

目录

一、短信发送

1.1 阿里云短信服务

1.1.1 设置短信签名

1.1.2 模板管理

1.1.3 设置AccessKey

1.2 短信发送——代码开发

1.2.1 导入maven坐标

1.2.2 调用API

1.2  手机验证码登录

1.2.1 用户数据库表

1.2.2  修改过滤器

1.2.3   随机生成验证码的工具类

1.2.4 手机验证码登录-- 发送验证码

1.2.5 手机验证码登录-- 验证验证码


一、短信发送

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.2  手机验证码登录

  • 方便、快捷、无需注册、直接登陆
  • 使用短信验证码作为登录凭证,无序记忆密码
  • 安全

登录流程:  输入手机号  ->  获取验证码  ->  输入验证码  ->  点击登录  ->  登陆成功

注意: 通过手机验证码登录,手机号是区分不同用户的标识

1.2.1 用户数据库表

因为是通过手机和验证码登录的,所以没有用户名和密码字段

1.2.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.2.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.2.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.2.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("登录失败");
    }

猜你喜欢

转载自blog.csdn.net/weixin_51351637/article/details/130188499