• SpringBoot 整合 redis 实现 token 验证


    SpringBoot 整合 redis 实现 token 验证

    在上一节中,实现了 SpringBoot + redis 的整合,因此在这里只列出必要部分的 redis 代码。

    1、Redis 依赖

    <!-- redis -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    

    2、Redis 配置

    2.1、properties 文件配置:

    spring.redis.port=6379
    spring.redis.host=127.0.0.1
    spring.redis.password=123456
    # 数据库索引(默认为0)
    spring.redis.database=15
    #最大连接数(使用负值表示没有限制)
    spring.redis.jedis.pool.max-active=100
    #最大空闲连接
    spring.redis.jedis.pool.max-idle=8
    #最小空闲连接
    spring.redis.jedis.pool.min-idle=0
    #最大阻塞等待时间(使用负值表示没有限制)
    spring.redis.jedis.pool.max-wait=60000
    #连接超时时间
    spring.redis.timeout=1000
    

    2.2、自定义配置类 RedisConfig

    @Configuration
    public class RedisConfig {
        @Bean
        public RedisTemplate<String, Object> template(RedisConnectionFactory factory) {
            //创建RedisTemplate<String,Object>对象
            RedisTemplate<String, Object> template = new RedisTemplate<>();
            //配置连接工厂
            template.setConnectionFactory(factory);
            //定义Jackson2JsonRedisSerializer序列化对象
            Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
            ObjectMapper objectMapper = new ObjectMapper();
            //指定要序列化的域,field,get和set,以及修饰符范围,ANY是包括private到public
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            //指定序列化输入的类型,类必须是非final修饰的,final修饰的类如String,Integer会报异常
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
            jsonRedisSerializer.setObjectMapper(objectMapper);
            StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
    
            // 值采用json序列化
            template.setValueSerializer(jsonRedisSerializer);
            //使用StringRedisSerializer来序列化和反序列化redis的key值
            template.setKeySerializer(new StringRedisSerializer());
    
            // 设置hash key 和value序列化模式
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setHashValueSerializer(jsonRedisSerializer);
            template.afterPropertiesSet();
            return template;
        }
    }
    

    2.3、redis 工具类 RedisUtils

    @Component
    public class RedisUtils {
        @Autowired
        private RedisTemplate<String, Object> redisTemplate;
    
        /**
         * 指定缓存失效时间
         *
         * @param key      键
         * @param time     时间
         * @param timeUnit 时间单位
         * @return
         */
        public boolean expire(String key, long time, TimeUnit timeUnit) {
            try {
                if (time > 0) {
                    redisTemplate.expire(key, time, timeUnit);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 根据key 获取过期时间
         *
         * @param key 键 不能为null
         * @return 时间(秒) 返回0代表为永久有效
         */
        public long getExpire(String key) {
            return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        }
    
        /**
         * 判断key是否存在
         *
         * @param key 键
         * @return true 存在 false不存在
         */
        public boolean hasKey(String key) {
            try {
                return redisTemplate.hasKey(key);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        
         /**
         * 删除缓存
         *
         * @param key 可以传一个值 或多个
         */
        @SuppressWarnings("unchecked")
        public void del(String... key) {
            if (key != null && key.length > 0) {
                if (key.length == 1) {
                    redisTemplate.delete(key[0]);
                } else {
                    redisTemplate.delete(CollectionUtils.arrayToList(key));
                }
            }
        }
    
        //============================String=============================
    
        /**
         * 普通缓存获取
         *
         * @param key 键
         * @return 值
         */
        public Object get(String key) {
            return key == null ? null : redisTemplate.opsForValue().get(key);
        }
    
        /**
         * 普通缓存放入
         *
         * @param key   键
         * @param value 值
         * @return true成功 false失败
         */
        public boolean set(String key, Object value) {
            try {
                redisTemplate.opsForValue().set(key, value);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    
        /**
         * 普通缓存放入并设置时间
         *
         * @param key      键
         * @param value    值
         * @param time     时间 time要大于0 如果time小于等于0 将设置无限期
         * @param timeUnit 时间单位
         * @return true成功 false 失败
         */
        public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
            try {
                if (time > 0) {
                    redisTemplate.opsForValue().set(key, value, time, timeUnit);
                } else {
                    set(key, value);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
    

    3、登录接口生成 token

    @GetMapping(value = "/tokenLogin")
    @ResponseBody
    public Result tokenLogin(String name, String password) {
        User user = userService.getOne(new QueryWrapper<User>().eq("name", name));
        if (user == null) {
            return ResultUtil.fail(1, "账号未注册");
        } else {
            //MD5加密
            String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
            if (!md5Password.equals(user.getPassword())) {
                return ResultUtil.fail(2, "密码错误");
            }
        }
        //生成token
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        //保存token,key为token,value为id,有效期为1个小时
        redisUtils.set(token, user.getId(), 1, TimeUnit.HOURS);
        return ResultUtil.success(token);
    }
    

    4、过滤器验证 token

    public class AccessFilter implements Filter {
        Logger logger = LoggerFactory.getLogger(AccessFilter.class);
    
        private RedisUtils redisUtils;
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //非Spring管理环境,需要手动注入Bean
            redisUtils = SpringUtils.getBean(RedisUtils.class);
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) servletRequest;
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            //登录接口跳过验证
            if (request.getRequestURI().contains("/tokenLogin")) {
                filterChain.doFilter(request, response);
                return;
            }
    
            /** token+redis验证 */
            String token = request.getHeader("token");
            if (!redisUtils.hasKey(token)) {
                logger.info("token过期,请重新登录");
                return;
            }
            //刷新token有效期
            redisUtils.expire(token, 1, TimeUnit.HOURS);
            filterChain.doFilter(request, response);
        }
    
        @Override
        public void destroy() {
        }
    }
    
    

    5、登出清除 token

    @GetMapping(value = "/tokenLogout")
    @ResponseBody
    public Result tokenLogout(HttpServletRequest request) {
        String token = request.getHeader("token");
        //删除redis的token
        redisUtils.del(token);
        return ResultUtil.success(0,"退出成功");
    }
    
    自我控制是最强者的本能-萧伯纳
  • 相关阅读:
    layer子层给父层页面元素赋值,以达到向父层页面传值的效果
    根据HttpServletRequest获取用户真实IP地址
    KVM--安装及初步使用
    eslint 踩坑 -- error '***' is assigned a value but never used no-unused-vars
    eslint 效验规则
    leetcode407接雨水II
    leetcodej剑指offer41.数据流中的中位数
    leetcode44通配符匹配
    leetcode955K连续位的最小反转次数
    leetcode638大礼包
  • 原文地址:https://www.cnblogs.com/CF1314/p/14722989.html
Copyright © 2020-2023  润新知