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,"退出成功");
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM