使用Redis缓存实现短信登录逻辑,手机验证码缓存,用户信息缓存

引入依赖

html 复制代码
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

加配置

bash 复制代码
spring:
  redis:
    host: 127.0.0.1  #redis地址
    port: 6379 #端口
    password: 123456 #密码,无密码可以注释调
    database: 10 #库
    lettuce:
      pool:
        max-active: 10 #最大连接数
        max-idle: 10 #最多空闲
        min-idle: 1 #至少空闲
        time-between-eviction-runs: 10s #连接空闲时间

定义登录校验拦截器

java 复制代码
/**
 * 拦截器
 */
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
     #校验是否登录,UserHolder中使用ThreadLocal保存用户信息
     if(UserHolder.getUser() == null){ 
         response.setStatus(401); //未登录响应401状态码
         return false;
     }
        return true; //放行
    }
}

定义刷新token拦截器(只用于刷新token时间)

java 复制代码
/**
 * 刷新token 拦截器
 */
public class RefreshTokenInterceptor implements HandlerInterceptor {
    private StringRedisTemplate stringRedisTemplate; //LoginInterceptor 是自己创建的不能autowire

    public RefreshTokenInterceptor(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //获取携带的token名
        String token = request.getHeader("authorization");
        if(StrUtil.isBlank(token)){
            return true;
        }

        //从redis中获取该token值
        String key = RedisConstants.LOGIN_USER_KEY+token;
        Map<Object, Object> userMap = stringRedisTemplate.opsForHash().entries(key);
        if(StrUtil.isBlank(token)){
            return true;
        }
        //将map转Bean
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
        UserHolder.saveUser(userDTO);
        //刷新token有效期
        stringRedisTemplate.expire(key,LOGIN_USER_TTL, TimeUnit.MINUTES);
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserHolder.removeUser();
    }
}

保存用户信息类:

java 复制代码
public class UserHolder {
    private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();

    public static void saveUser(UserDTO user){
        tl.set(user);
    }

    public static UserDTO getUser(){
        return tl.get();
    }

    public static void removeUser(){
        tl.remove();
    }
}

新建配置类LoginConfig,添加自己定义的拦截器

java 复制代码
@Configuration
public class MVCConfig implements WebMvcConfigurer {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(new LoginInterceptor())
            .excludePathPatterns( //添加排除路径
                "/user/code",
                "/user/login",
        ).order(1); //order值越小越先执行,值相等则先添加先执行
        
        registry.addInterceptor(new RefreshTokenInterceptor(stringRedisTemplate)).order(0);
    }

}

登录逻辑

复制代码
校验手机号 --> 校验验证码 --> 检查用户是否存在 --> 生成token --> 将用户信息user转成Hash存储到redis中 --> 设置token有效期

其中token可用hutool的UUID生成: UUID.randomUUID().toString(true); //true是不要短横线 -

将用户实体转成Map集合,存放到redis中:

java 复制代码
Map<String, Object> userMap = BeanUtil.beanToMap(userDTO,new HashMap<>(),
                CopyOptions.create()
                .setIgnoreNullValue(true)
                .setFieldValueEditor((fieldName,fieldValue)-> fieldValue.toString())); //所有字段值转为String
        //存redis
        String tokenKey = LOGIN_USER_KEY + token;
        stringRedisTemplate.opsForHash().putAll(tokenKey,userMap);

设置Token有效期

java 复制代码
        //设置token有效期
        stringRedisTemplate.expire(tokenKey,LOGIN_USER_TTL,TimeUnit.MINUTES); //分钟

手机号验证,可添加一个插件,快捷查询各种校验的正则表达式:

将验证码存入redis并设置验证码有效期

java 复制代码
         //模拟生成验证码
        String code = RandomUtil.randomNumbers(6);
        //手机号唯一
        stringRedisTemplate.opsForValue().set(LOGIN_CODE_KEY + phone, code, LOGIN_CODE_TTL, TimeUnit.MINUTES);

常量命名规范:

java 复制代码
    public static final String LOGIN_CODE_KEY = "login:code:"; //验证码的key
    public static final Long LOGIN_CODE_TTL = 2L; //验证码的有效期
    public static final String LOGIN_USER_KEY = "login:token:"; //token的key
    public static final Long LOGIN_USER_TTL = 30L; //token的有效期
相关推荐
NCIN EXPE7 小时前
redis 使用
数据库·redis·缓存
hERS EOUS7 小时前
nginx 代理 redis
运维·redis·nginx
NoSi EFUL8 小时前
redis存取list集合
windows·redis·list
Deepincode9 小时前
Redis源码探究系列—SDS 扩容策略与内存预分配机制
redis
老神在在00110 小时前
Spring Bean 的六种作用域详解
java·后端·spring
程序员老邢10 小时前
【技术底稿 19】Redis7 集群密码配置 + 权限锁死 + 磁盘占满连锁故障真实排查全记录
java·服务器·经验分享·redis·程序人生·微服务
Rick199311 小时前
Spring AI 如何进行权限控制
人工智能·python·spring
coNh OOSI11 小时前
Redis——Windows安装
数据库·windows·redis
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.11 小时前
Redis主从复制配置全攻略
数据库·redis·笔记
csdn2015_12 小时前
修改分类信息的时候将分类异步写入redis
数据库·redis·bootstrap