Reggie外卖项目 —— 移动端小程序之手机验证码登录

23、手机验证码登录

23.1、需求分析

1、为了方便用户登录,移动端通常都会提供通过手机验证码登录的功能。

2、手机验证码登录的优点:

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

3、登录流程:

输入手机号码>获取验证码>输入验证码>点击登录>登录成功

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

23.2、数据模型

通过手机验证码登录时,涉及的表为user表,即用户表。结构如下:

在这里插入图片描述

23.3、代码开发

23.3.1、梳理交互过程

在开发代码之前,需要梳理一下登录时前端页面和服务端的交互过程:

1、在登录页面(front/page/login.html)输入手机号,点击【获取验证码】按钮,页面发送ajax请求,在服务端调用短信服务API给指定的手机号发送验证码短信。

2、在登录页面输入验证码,点击【登录】按钮,发送ajax请求,在服务端处理登录请求

开发手机验证码登录功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。

23.3.2、准备工作

在开发业务功能前,先将需要用到的类和接口基本结构创建好:

  • 实体类User

    /**
     * 用户信息
     */
    @Data
    public class User implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private Long id;
    
        //姓名
        private String name;
    
        //手机号
        private String phone;
    
        //性别 0 女 1 男
        private String sex;
    
        //身份证号
        private String idNumber;
    
        //头像
        private String avatar;
    
        //状态 0:禁用,1:正常
        private Integer status;
    }
    
  • Mapper接口UserMapper

    @Mapper
    public interface UserMapper extends BaseMapper<User> {
    }
    
  • 业务层接口Userservice

    public interface UserService extends IService<User> {
    }
    
  • 业务层实现类UserServiceImpl

    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    }
    
  • 控制层UserController

    @RestController
    @RequestMapping("/user")
    @Slf4j
    public class UserController {
    
        @Autowired
        private UserService userService;
    }
    
  • 工具类SMSUtilsvalidateCodeUtils

    SMSUtils.java

    /**
     * 短信发送工具类
     */
    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", "", "");
          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+"\"}");
          try {
             SendSmsResponse response = client.getAcsResponse(request);
             System.out.println("短信发送成功");
          }catch (ClientException e) {
             e.printStackTrace();
          }
       }
    
    }
    

    validateCodeUtils.java

    /**
     * 随机生成验证码工具类
     */
    public class ValidateCodeUtils {
        /**
         * 随机生成验证码
         * @param length 长度为4位或者6位
         * @return
         */
        public static Integer generateValidateCode(int length){
            Integer code =null;
            if(length == 4){
                code = new Random().nextInt(9999);//生成随机数,最大为9999
                if(code < 1000){
                    code = code + 1000;//保证随机数为4位数字
                }
            }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;
        }
    }
    

23.3.3、修改LoginCheckFilter

1、前面我们已经完成了LoginCheckFilter过滤器的开发,此过滤器用于检查用户的登录状态。我们在进行手机验证码登录时,发送的请求需要在此过滤器处理时直接放行。

//定义不需要处理的请求路径
String[] urls = new String[]{
        "/employee/login",
        "/employee/logout",
        "/backend/**",
        "/front/**",
        "/common/**",
        "/user/sendMsg",//移动端发送短信
        "/user/login" //移动端登录
};

2、在LoginCheckFilter过滤器中扩展逻辑,判断移动端用户登录状态:

//4-2、判断登录状态,如果已登录,则直接放行
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;
}

23.4、功能测试

23.4.1、发送手机验证码

1、前端开发

在这里插入图片描述

2、Controller开发

/**
 * 发送手机验证码
 * @param user
 * @return
 */
@PostMapping("/sendMsg")
public R<String> sendMsg(@RequestBody User user, HttpSession session) {
    //获取手机号
    String phone = user.getPhone();

    if (StringUtils.isNotEmpty(phone)) {
        //生成随机的4位验证码
        String code = ValidateCodeUtils.generateValidateCode(4).toString();
        log.info("code={}", code);

        //调用阿里云提供的短信服务API完成发送短信
        //SMSUtils.sendMessage("瑞吉外卖", "", phone, code);

        //需要将生成的验证码保存到Session
        session.setAttribute(phone, code);
        return R.success("手机验证码短信发送成功");
    }
    return R.error("手机验证码短信发送失败");

}

23.4.2、移动端登录

1、前端开发

在这里插入图片描述

2、Controller开发

/**
 * 移动端用户登录
 * @param map
 * @param session
 * @return
 */
@PostMapping("/login")
public R<User> login(@RequestBody Map map, HttpSession session) {
    log.info(map.toString());
    //获取手机号
    String phone = map.get("phone").toString();

    //获取验证码
    String code = map.get("code").toString();

    //从Session获取保存的验证码
    String codeInSession = session.getAttribute(phone).toString();

    //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
    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();
            user.setPhone(phone);
            user.setStatus(1);
            userService.save(user);
        }
        session.setAttribute("user",user);
        return R.success(user);
    }

    return R.error("登录失败");
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值