短信登录:

基于Redis缓存:


(1)发送短信验证码:

实现逻辑 :

  1. 先校验手机号 ,

    1. 不符合

      1. 直接返回错误信息 , 使用的是封装的返回前端的方法
    2. 符合 ,
      1. 生成一个随机验证码 , 使用的是huTool中的RandomUtil工具类 , 生成随机的六位验证码
      2. 保存验证码到Redis中 , 使用手机号加前缀作为key值保存 , 保证key值唯一性 , 同时设置验证码有效时间
      3. 返回前端数据

代码实现 :

@Override
public Result sendCode(String phone) {//TODO 1.校验手机号:不符合是trueif (RegexUtils.isPhoneInvalid(phone)) {//2.如果不符合 , 返回错误信息return Result.fail("手机号格式错误");}// TODO 3.符合 , 生成一个随机验证码 , 使用的是huTool中的工具类 ,String code = RandomUtil.randomNumbers(6);// TODO 4.保存验证码到Redis当中 , 使用手机号加前缀作为key来保存 , 保证可以的唯一性 , 同时 , 设置有效期为两分钟stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);//5.模拟发送验证码log.debug("发送短信验证码成功, 验证码:{" + code + "}");//6.返回前端数据okreturn Result.ok();
}

(2)短信验证码登录注册:

实现逻辑 :

  1. 校验手机号 ,

    1. 不符合

      1. 就直接返回错误信息 , 避免有人使用正确手机号获取验证码 , 但是注册时切换错误手机号
    2. 符合
      1. 从Redis中获取验证码 ,

        1. 判断验证码是否失效(也就是验证码查询不出来) 或者 校验用户输入验证码和Redis中的验证码是否一致

          1. 不符合

            1. 直接输出错误信息
          2. 符合
            1. 从数据库中根据手机号查询用户信息

              1. 查询不出来

                1. 创建新用户 , 使用随机的字符串加前缀作为用户名
              2. 查询出来
            2. 将获取的用户信息选择拷贝搭配DTO类中 , (隐藏用户隐私信息)
            3. 将UserDTO类转换为map类型数据 ,
            4. 设置一个随机字符串和前缀作为该用户的登录令牌
            5. 将令牌作为key , UserDTO作为key进行缓存 , 使用map格式作为缓存数据类型
            6. 将获取的UserDTO返回前端

代码实现 :

@Override
public Result login(LoginFormDTO loginForm) {//1.校验手机号String phone = loginForm.getPhone();if (RegexUtils.isPhoneInvalid(phone)) {return Result.fail("手机号格式错误");}//2. TODO 校验验证码 , 从redis中获取验证码String cacheCode = stringRedisTemplate.opsForValue().get(LOGIN_CODE_KEY + phone);String code = loginForm.getCode();if (cacheCode == null || !cacheCode.equals(code)) {//3.判断验证码是否失效(也就是验证码查询不出来) 或者 校验用户输入验证码和Redis中的验证码是否一致return Result.fail("验证码错误");// TODO 使用反证的方式 , 可以减少if语句的判断次数}//4.一致 , 根据手机号查询用户// TODO 使用的是MyBatisPlus中的方法 , 进行查询的User user = query().eq("phone", phone).one();//5.判断用户是否存在if (user == null) {//6.不存在 , 创建新用户并保存user = createUserWithPhone(phone);}// TODO 7.保存用户信息到redis中// TODO 7.1 随机生成token作为登录令牌// TODO 使用huTool提供的UUID , 下边的写法是生成不带下划线的UUID , 默认值为false,带下划线的UUIDString token = UUID.randomUUID().toString(true);// TODO 使用BeanUtil中的copyProperties方法 , 可以将user中的属性自动拷贝到UserDTO中 , 对于没有的属性,不进行拷贝UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);// TODO 7.2 将User对象转为Hash集合 , 将UserDTO转换为一个Map集合 ,//  这个时候 , 进行转换的时候 ,会出现异常 , 因为我们使用的是String类型的redis对象 , 在转换的时候 , key值只能是String类型的//  但是 , 这个BeanUtil工具类 , 允许我们进行自定义 ,//  添加两个参数 , 一个是new HashMap<>() ,//  一个是CopyOptions , 定义自定义的操作Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),CopyOptions.create().setIgnoreNullValue(true) // TODO 设置是否忽略空值// TODO 对字段值的修改器 , 需要两个参数 , 修改前的字段名和字段值 , 修改后的字段值.setFieldValueEditor((fileName,fileValue) -> fileValue.toString()));// TODO 7.3 存储String tokenKey = LOGIN_USER_KEY + token;stringRedisTemplate.opsForHash().putAll(tokenKey, userMap);// TODO 7.4 设置token的有效期 , redis中不能在上一个方法中直接设置有效期 , 可以在下边设置stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES);// TODO 8.返回token , 用来将这个token保存在浏览器中 , 下次登录的时候 , 会携带这个token进行访问return Result.ok(token);
}//TODO 创建用户
private User createUserWithPhone(String phone) {//1.创建用户 :User user = new User();user.setPhone(phone);//生成随机的字符串 , 用来当做用户名user.setNickName("user_" + RandomUtil.randomString(10));save(user);return user;
}

(3)拦截是否有登录令牌 , 有就刷新 , 没有就直接放行

  • 使用拦截器 , 负责检测用户登录的时间 , 使用缓存 token来定义用户的登录时间 , 只要有操作 , 就刷新token的时间 ,

  • 只负责检测请求中有没有携带token , 没有就直接放行 , 有了就刷新token ,


实现逻辑 :

  1. 设置前置拦截 , 获取请求头中的token

    1. 为空 , 说明没有登录 , 使用isBlank判断 ,

      1. 直接放行
    2. 不为空 , 获取Redis中的用户的信息
      1. 判断获取的map集合是否为空

        1. 为空 , 直接放行
        2. 不为空 , 将获取到的信息转为Map格式 , 存储在ThreadLocal域中
        3. 刷新token的有效期

代码实现 :

/*** 拦截器类 , 负责刷新token保存时间的 , 只有用户登录了才进行操作 , 其他的一概放行*/
public class RefreshTokenInterceptor implements HandlerInterceptor {// TODO 注意: 拦截器是我们自己创建的类 , 不受Spring容器管理 , 所以 , 不能直接注入RedisTemplate// TODO 我们只能使用构造函数的方式进行注入 , 谁调用这个拦截器 ,谁负责注入这个RedisTemplateprivate StringRedisTemplate stringRedisTemplate;public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}@Override//前置拦截public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// TODO 1.获取请求头中的tokenString token = request.getHeader("authorization");// TODO StrUtil中的isBlank方法就是判断是否是空值if (StrUtil.isBlank(token)){// TODO 为空,说明没有登录 , 直接放行return true;}// TODO 2.基于token获取redis中的用户信息// TODO 不能简单的使用get来获取值了 , 使用get获取的只是hash中的map中的一个值 , 而我们想获取的是全部的值 , 使用entries这个方法Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(RedisConstants.LOGIN_USER_KEY + token);// TODO 不用判断是否为null了,entries会做判断 , 如果为null会返回一个空的map , 所以这里只用判断是否为空就可以了if (userMap.isEmpty()){// TODO 为空说明用户没有登录, 直接放行 , 不作操作return true;}// TODO 不为空 , 进行token以及数据的保存工作// TODO 5.将查询到的Hash数据转为UserDTO对象 , 最后一个参数是否忽略转换中的异常 , false是不忽略UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);// TODO 5.存在 , 保存用户信息到ThreadLocal , 这是一个工具类 , 内部创建了一个ThreadLocal对象,来进行操作UserHolder.saveUser(userDTO);// TODO 7.刷新token的有效期 , 也就是从新设置对应key的有效时间stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY+ token,LOGIN_USER_TTL, TimeUnit.MINUTES);//6.放行return true;}@Override//后置拦截public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {//删除用户UserHolder.removeUser();}

(4)拦截是否登录 :

有了第一个拦截器 , 这个类 就只用拦截是否登录即可 ,

实现逻辑 :

  1. 从ThreadLocal域中获取用户信息 .

    1. 只要为null , 就说明没有登录 , 直接拦截
    2. 不为null , 放行

代码实现 :

/*** 拦截器类 , 负责拦截是否登录的*/
public class LoginInterceptor implements HandlerInterceptor {@Override//前置拦截public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// TODO 1.判断是否需要拦截 , ThreadLocal中是否有用户信息if (UserHolder.getUser() == null){// 没有 , 需要拦截 , 设置状态码 ,response.setStatus(401);// 拦截return false;}//有用户 , 直接放行return true;}
}

(5)拦截器的配置类:

@Configuration
// TODO 配置拦截器
public class MvcConfig implements WebMvcConfigurer {@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic void addInterceptors(InterceptorRegistry registry) {// TODO token 刷新拦截器registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0); // TODO 设置优先级 ,值越小 , 优先级越高registry.addInterceptor(new LoginInterceptor()).excludePathPatterns("/blog/hot","/shop-type/**","/upload/**","/voucher/**","/shop/**","/user/code","/user/login").order(1);}
}
     .excludePathPatterns("/blog/hot","/shop-type/**","/upload/**","/voucher/**","/shop/**","/user/code","/user/login").order(1);
}

}


---

1.Redis实战—短信登录相关推荐

  1. Redis实战——短信登录

    目录 1 基于Seesion实现短信登录 1.1 发送短信验证码 1.2 登录功能 2 使用Redis进行短信验证码校验登录 2.1 Seesion方法存在的问题 2.2 发送短信验证码 2.3  验 ...

  2. 24、短信登录(基于redis实现短信登录)

    短信登录(基于redis实现短信登录) 修改代码(之前的基于session) 发送验证的逻辑:(更改就是将短信验证码存到redis中) 第一步:注入SrtingRedisTemplate (users ...

  3. 《Redis实战篇》一、短信登录

    1.1.导入黑马点评项目 1.1.1 .导入SQL 1.1.2.有关当前模型 手机或者app端发起请求,请求我们的nginx服务器,nginx基于七层模型走的事HTTP协议,可以实现基于Lua直接绕开 ...

  4. 基于Session实现短信登录

    目录 一.基于Session实现登录 1.1 业务流程图​编辑 二.发送短信验证码 2.1 发送短信请求方式及参数说明 2.2 业务层代码模拟发送短信 三.登录功能 3.1  短信验证的请求方式及路径 ...

  5. redis的实战项目01_模拟短信登录业务

    redis的实战项目01_短信登录 一.导入黑马点评项目 1. 数据库: 2. 单体项目介绍: 二.基于session实现登录 1.发送短信验证码 1.理论流程 2.代码操作: 2.短信验证码登录.注 ...

  6. Redis(五) - Redis企业实战之短信登录

    文章目录 一.导入黑马点评项目 1. 导入SQL 2. 前后端分离 3. 导入后端项目 3.1 将后端项目导入到 Idea 中 3.2 注意:修改application.yaml文件中的mysql.r ...

  7. Redis框架(三):大众点评项目 基于Session的短信登录

    大众点评项目 基于Session的短信登录 需求:基于Session实现短信验证登录 基于Session的短信登录 发送手机验证码 实现登录 (注意MyBatisP的接口使用) 新的问题 Spring ...

  8. Redis(2)短信验证码登录

    Redis实现短信验证码登录 登录流程 1.发送验证码: 2.短信验证码登录,注册 3.校验登录状态 解决状态登录刷新问题 redis指令参考:https://blog.csdn.net/weixin ...

  9. 黑马点评项目-短信登录功能

    一.导入黑马点评项目 1.代码下载 视频资源链接:P25 实战篇-02.短信登录-导入黑马点评项目 代码可以直接去黑马微信公众号上搜索,或者从下面的网盘链接中下载:链接: https://pan.ba ...

最新文章

  1. 一键安装MySQL5.6.43脚本
  2. WinXP下替代IIS的新思路
  3. PTA — 表格输出 (5 分)
  4. 使用Java Api 操作HDFS
  5. dell服务器怎么用u盘系统安装win7系统教程,戴尔DellU盘重装系统操作教程
  6. BZOJ 3173: [Tjoi2013]最长上升子序列 [splay DP]
  7. 有关 VS winform 开发问题
  8. matlab钢琴音教程,弹琴吧 - 今天聊一聊钢琴扒带及MIDI制作,使用音
  9. DIY智能小车篇(四):常见问题 BUG汇总
  10. redis指定配置文件启动不生效_redis配置文件不生效
  11. 服务器装系统提示未找到任何驱动器,win7系统安装时提示找不到任何设备驱动程序的四种解决方法图文教程...
  12. 如何做好一名合格的项目组长
  13. 跟着弦哥学人工智能2—HAND-CRAFTED RULES实现的人工智能及其缺陷
  14. 团队管理之亮剑精神(转)
  15. JVM(5)_方法区和大厂面试题
  16. 2020.9.28(Hive视图、索引、权限管理)
  17. android 三大框架是什么,聊聊Android中的三大框架
  18. PyQt5端口映射TCP/UDP工具
  19. 人大金仓(kingbase8)安装与初始化超详细教程
  20. element input自定义正则验证

热门文章

  1. 什么是dbunit以及为什么要使用它
  2. 【环境搭建】linux上pip换源
  3. duang!京东瞬间成了一只受伤的狗!
  4. 彻底解决windows XP 的启动问题 微软官方资料
  5. java 解析rmc_GPS 0183协议GGA、GLL、GSA、GSV、RMC、VTG解释 + 数据解析 | 技术部落
  6. 攻防世界MISC_掀桌子
  7. 什么是认购期权与认沽期权!
  8. 【java jar包 linux 部署】
  9. Java学习日记Day11(面向对象day05)
  10. MySql查询语句方法