Java - SpringBoot整合Shiro之缓存功能
创始人
2024-01-21 06:08:58
0

Java - SpringBoot整合Shiro之缓存功能

  • 前言
  • 一. SpringBoot 整合Redis
    • 1.1 配置 RedisTemplate
    • 1.2 Shiro整合Redis缓存配置
    • 1.3 测试

前言

在 上一篇文章 主要讲了Shiro权限授权和认证跳过。本篇文章就主要讲解如何整合ShiroRedis。这样就避免携带同一个Token的时候,每次取查询数据库了。可以利用一个缓存,减轻DB的压力。

一. SpringBoot 整合Redis

添加pom依赖:


org.springframework.bootspring-boot-starter-data-redis

1.1 配置 RedisTemplate

我们可以在application.yml文件中添加Redis相关的配置:

spring:redis:database: 0 # Redis数据库索引(默认为0)host: xxx # Redis的服务地址port: xxx # Redis的服务端口password: xxx # Redis密码jedis:pool:max-active: 8 # 连接池最大连接数(使用负值表示没有限制)max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)max-idle: 8 # 连接池中的最大空闲连接min-idle: 0 # 连接池中的最小空闲链接timeout: 30000 # 连接池的超时时间(毫秒)

添加Redis的配置类RedisConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;/*** @Date 2022/11/15 13:56* @Created by jj.lin*/
@Configuration
public class RedisConfig {/*** 实例化 RedisTemplate 对象** @return*/@Beanpublic RedisTemplate functionDomainRedisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate redisTemplate = new RedisTemplate<>();initDomainRedisTemplate(redisTemplate, redisConnectionFactory);return redisTemplate;}/*** 设置数据存入 redis 的序列化方式,并开启事务** @param redisTemplate* @param factory*/private void initDomainRedisTemplate(RedisTemplate redisTemplate, RedisConnectionFactory factory) {// 配置序列化器。如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());// 开启事务redisTemplate.setEnableTransactionSupport(true);redisTemplate.setConnectionFactory(factory);}
}

1.2 Shiro整合Redis缓存配置

1.我们自定义一个缓存管理器RedisCacheManager,需要继承CacheManager

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;/*** @Date 2022/11/15 13:52* @Created by jj.lin*/
public class RedisCacheManager implements CacheManager {@Overridepublic  Cache getCache(String s) throws CacheException {return new RedisCache(s);}
}

2.上面的RedisCache是我们自定义的实现,我们需要重写相关的put/get函数。这样Shiro在认证的时候,就会通过我们自定义的put/get函数去存储/获得缓存了。

import com.pro.config.SpringBeanUtil;
import com.pro.constant.JwtConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;/*** @Date 2022/11/15 13:52* @Created by jj.lin*/
@Slf4j
public class RedisCache implements Cache {private String cacheName;public RedisCache(String cacheName) {this.cacheName = cacheName;}private RedisTemplate getRedisTemplate() {RedisTemplate redisTemplate = SpringBeanUtil.getBean(RedisTemplate.class);return redisTemplate;}@Overridepublic V get(K k) throws CacheException {RedisTemplate redisTemplate = getRedisTemplate();V v = (V) redisTemplate.opsForHash().get(cacheName, k.toString());Long expire = redisTemplate.getExpire(cacheName);log.info("从 {} 中获取Key:{}, Value:{},剩余缓存时长:{}", cacheName, k, v, expire);return v;}@Overridepublic V put(K k, V v) throws CacheException {log.info("从 {} 中插入Key:{}, Value:{}", cacheName, k, v);RedisTemplate redisTemplate = getRedisTemplate();redisTemplate.opsForHash().put(cacheName, k.toString(), v);// 可以设置一个缓存的超时时间redisTemplate.expire(cacheName, JwtConstant.TIMEOUT, TimeUnit.MINUTES);return null;}@Overridepublic V remove(K k) throws CacheException {return (V) getRedisTemplate().opsForHash().delete(cacheName, k.toString());}@Overridepublic void clear() throws CacheException {getRedisTemplate().delete(cacheName);}@Overridepublic int size() {return getRedisTemplate().opsForHash().size(cacheName).intValue();}@Overridepublic Set keys() {return getRedisTemplate().opsForHash().keys(cacheName);}@Overridepublic Collection values() {return getRedisTemplate().opsForHash().values(cacheName);}
}

3.常量JwtConstant

public class JwtConstant {public static final String USER_ID = "userId";public static final Integer TIMEOUT = 10;
}

4.然后Shiro开启缓存功能的配置ShiroConfig

原代码:
@Bean
public Realm realm() {JwtRealm jwtRealm = new JwtRealm();return jwtRealm;
}
新代码:
@Bean
public Realm realm() {JwtRealm jwtRealm = new JwtRealm();// 开启缓存,设置缓存管理器jwtRealm.setCachingEnabled(true);jwtRealm.setAuthenticationCachingEnabled(true);jwtRealm.setAuthorizationCachingEnabled(true);jwtRealm.setCacheManager(new RedisCacheManager());return jwtRealm;
}

1.3 测试

1.我们先登录一下:拿到一个最新的Token
在这里插入图片描述

2.第一次访问getUser接口(需要经过JWT认证):
在这里插入图片描述
为什么这里有两次插入?因为我getUser接口还有身份校验的过程:

@RequiresRoles("user")
@PostMapping("/getUser")
public String getUser() {Long userId = JwtUtil.getUserId();Subject currentUser = SecurityUtils.getSubject();if (userId != null) {return "成功拿到用户信息: " + currentUser.getPrincipal();}return "用户信息为空";
}

相当于:

  • doGetAuthenticationInfo:第一次认证的时候,插入了一条缓存。
  • doGetAuthorizationInfo:第二次身份校验的时候,又更新了一次缓存。

3.第二次访问:可见没有插入的日志了。同时Degbug打个断点也能发现,上面两个函数,只有第一次执行的时候会访问。后续就不会再进入了。因为缓存的原因。
在这里插入图片描述

我们存入Redis中的hashKey就是我们的Token。所以在有效时间内,带着相同Token的请求,都不需要经过认证了。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...