Redis实现短信登录

发送验证码

前端请求后,校验手机号后使用UUID等工具生成6位随机数,将其保存到redis中

//生成验证码
String code = RandomUtil.randomNumbers(6);
​
//保存验证码到redis(String)
stringRedisTemplate.opsForValue().set("login:code:" + phone, code, 5, TimeUnit.MINUTES);

验证验证码

String cacheCode = stringRedisTemplate.opsForValue().get("login:code:" + phone);

校验登录状态

// 登录时会生成一个token响应给前端,并将此token绑定用户对象的信息
String token = UUID.randomUUID().toString();
stringRedisTemplate.opsForHash().putAll("login:token:" + token, usermap);
​
/*注册拦截器, 这里拦截器主要有两个用途
一是:拦截未经登录就请求需要登录时才能访问的资源。
二是:将用户信息保存在线程中(也就是该线程将陪伴用户此后的整个过程)方便取到后面请求再次需要用到该用户的信息(如: 评论会将此时保存的用户名、头像等信息取出交给前端显示在评论区)。*/
​
// 需要两个拦截器的原因:这里RefreshTokenInterceptor负责将用户信息存到线程&&刷新token时效(token的时效有限,但如果用户一直在请求资源,则token的时间一直被刷新)。如果一个拦截器那么他只会在访问需要登录的资源才会刷新token,不需要拦截的资源不会经过拦截器自然不会经过此方法进行刷新。
​
//RefreshTokenInterceptor: 将用户信息存到线程中,处理完后交给下一个登录拦截器
@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 1.获取请求头中的token
        String token = request.getHeader("authorization");
        if (StrUtil.isBlank(token)) {
            return true;
        }
        // 2.基于TOKEN获取redis中的用户
        String key  = LOGIN_USER_KEY + token;
        Map userMap = stringRedisTemplate.opsForHash().entries(key);
        // 3.判断用户是否存在
        if (userMap.isEmpty()) {
            return true;
        }
        // 5.将查询到的hash数据转为UserDTO
        UserDTO userDTO = BeanUtil.fillBeanWithMap(userMap, new UserDTO(), false);
        // 6.存在,保存用户信息到 ThreadLocal
        UserHolder.saveUser(userDTO);
        // 7.刷新token有效期
        stringRedisTemplate.expire("login:token:" + token, 1, TimeUnit.DAYS);
        // 8.放行
        return true;
    }
@Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //整个请求处理完成后移除用户信息
        UserHolder.removeUser();
    }
​
​
// LoginInterceptor: 拦截线程中没有用户信息的所有请求
@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //所有工作已经在RefreshTokenInterceptor里做了, 所以该拦截器只做判断是否要拦截
        if (UserHolder.getUser() == null){
            response.setStatus(401);
            return false;
        }
        return true;
    }
​
​
​
// 注册拦截器、添加需要拦截的路径资源
@Configuration
public class MvcConfig implements WebMvcConfigurer {
​
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private LoginInterceptor loginInterceptor;
    @Resource
    private RefreshTokenInterceptor refreshTokenInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 登录拦截器
        registry.addInterceptor(loginInterceptor)
                .excludePathPatterns(
                        "/shop/**",
                        "/voucher/**",
                        "/shop-type/**",
                        "/upload/**",
                        "/blog/hot",
                        "/user/code",
                        "/user/login"
                ).order(1);
        // token刷新的拦截器
        registry.addInterceptor(refreshTokenInterceptor.addPathPatterns("/**").order(0);
    }
}

你可能感兴趣的:(Redis必知会,redis,java,spring)