使用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的有效期
相关推荐
IT大白鼠5 天前
Redis 系列 · 第 01 篇——认知入门:Redis 是什么
redis·nosql
彧azz5 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
Bingo_BIG5 天前
Java Spring框架:单表的查询、新增、修改、删除、导入、导出
java·spring·前后端
全栈弄潮儿²⁰²⁴5 天前
AI Agent 开发实战(30):限流、缓存与成本控制
人工智能·gpt·缓存·agent·限流·agi·成本控制
lbb 小魔仙5 天前
OpenClaw + cpolar 实战:远程 NAS、分享小游戏、RDP,再配置公网 AI 入口
数据库·人工智能·redis·oracle·prometheus
paopaokaka_luck5 天前
智慧社区综合服务小程序(人脸识别、AI问答、Echarts图形化分析)
前端·javascript·spring boot·spring·数据分析·echarts
牧瀬クリスだ5 天前
YAML配置详解:SpringBoot实战指南
java·spring·yml
需要8265 天前
JVM 内存区域与对象创建:一次 GC 从哪来
java·jvm·spring boot·spring·servlet·tomcat
夕除5 天前
redis--018
redis
两锭子5 天前
Redis基础
redis