[Shiro入门](一)使用Redis作为缓存管理器
来源:互联网 发布:辐射4低配优化补丁 编辑:程序博客网 时间:2024/06/03 14:53
简述
Shiro提供了类似Spring的Cache抽象,即Shiro本身不实现Cache,但是对Cache进行了又抽象,方便更换不同的底层Cache实现,而Shiro官方提供了对于Ehcache缓存的支持,并提供了shiro-ehcache.jar的包。但是我们想要用Redis来作为缓存管理器,Ehcache和Redis的优劣可以去自行百度。后面我也会通过查资料总结一下的。
Shiro提供的接口
- Shiro提供的Cache接口:
public interface Cache<K, V> { //根据Key获取缓存中的值 public V get(K key) throws CacheException; //往缓存中放入key-value,返回缓存中之前的值 public V put(K key, V value) throws CacheException; //移除缓存中key对应的值,返回该值 public V remove(K key) throws CacheException; //清空整个缓存 public void clear() throws CacheException; //返回缓存大小 public int size(); //获取缓存中所有的key public Set<K> keys(); //获取缓存中所有的value public Collection<V> values(); }
- Shiro提供的CacheManager接口
public interface CacheManager { //根据缓存名字获取一个Cache public <K, V> Cache<K, V> getCache(String name) throws CacheException; }
- Shiro提供了CacheManagerAware用户注入CacheManager
public interface CacheManagerAware { //注入CacheManager void setCacheManager(CacheManager cacheManager); }
Shiro内部响应的组件(DefaultSecurityManager)会自动检测响应的对象(如Realm)是否实现了CacheManagerAware并自动注入响应的CacheManager。
配置缓存管理器
我们要使用Redis作为缓存管理器,那么我们就需要实现这些接口,但是前提是我们要在Spring-Shiro.xml中配置缓存管理器。
<!--1. 安全管理器--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="customCacheManager"/> <property name="realms"> <list> <ref bean="shiroRealm"/> </list> </property> </bean> <!--2. 自定义Realm--> <bean id="shiroRealm" class="com.why.authority.realms.ShiroRealm"> <!-- 依赖凭证匹配器 --> <property name="credentialsMatcher" ref="credentialsMatcher"/> <!--启用缓存,默认关闭--> <property name="cachingEnabled" value="true"/> <!--启用身份验证缓存,即缓存AuthenticationInfo,默认false--> <property name="authenticationCachingEnabled" value="true"/> <!--启用授权缓存,即缓存AuthorizationInfo的信息,默认为false--> <property name="authorizationCachingEnabled" value="true"/> </bean> <!--6. 会话管理器--> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!--删除在session过期时跳转页面时自动在URL中添加JSESSIONID--> <property name="sessionIdUrlRewritingEnabled" value="false" /> <!-- 设置超时时间 --> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionIdCookieEnabled" value="true"/> </bean> <!-- 7. 缓存管理器--> <!-- 7.1 这里配置我们自定义的缓存管理器--> <bean id="customCacheManager" class="com.why.authority.cache.CustomCacheManager"/>
创建RedisCache实现Cache接口
package com.why.authority.cache;import com.why.utils.jedis.JedisClientSingle;import com.why.utils.serializable.ByteSourceUtils;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import redis.clients.jedis.Jedis;import java.io.Serializable;import java.util.*;/** * @author: 王洪玉 * @decsription: 缓存管理器 * @create: 2017/12/5 21:18 * @modified By: */public class RedisCache<K,V> implements Cache<K,V> { public String getKeyPrefix() { return keyPrefix; } public void setKeyPrefix(String keyPrefix) { this.keyPrefix = keyPrefix; } private String keyPrefix = "shiro_redis_session:"; /** * 获得byte[]型的key * @param key * @return */ private byte[] getByteKey(Object key){ if(key instanceof String){ String preKey = this.keyPrefix + key; return preKey.getBytes(); }else{ return ByteSourceUtils.serialize((Serializable) key); } } @Override public Object get(Object key) throws CacheException { byte[] bytes = getByteKey(key); byte[] value = JedisClientSingle.getJedis().get(bytes); if(value == null){ return null; } return ByteSourceUtils.deserialize(value); } /** * 将shiro的缓存保存到redis中 */ @Override public Object put(Object key, Object value) throws CacheException { Jedis jedis = JedisClientSingle.getJedis(); jedis.set(getByteKey(key), ByteSourceUtils.serialize((Serializable)value)); byte[] bytes = jedis.get(getByteKey(key)); Object object = ByteSourceUtils.deserialize(bytes); return object; } @Override public Object remove(Object key) throws CacheException { Jedis jedis = JedisClientSingle.getJedis(); byte[] bytes = jedis.get(getByteKey(key)); jedis.del(getByteKey(key)); return ByteSourceUtils.deserialize(bytes); } /** * 清空所有缓存 */ @Override public void clear() throws CacheException { JedisClientSingle.getJedis().flushDB(); } /** * 缓存的个数 */ @Override public int size() { Long size = JedisClientSingle.getJedis().dbSize(); return size.intValue(); } /** * 获取所有的key */ @Override public Set keys() { Set<byte[]> keys = JedisClientSingle.getJedis().keys(new String("*").getBytes()); Set<Object> set = new HashSet<Object>(); for (byte[] bs : keys) { set.add(ByteSourceUtils.deserialize(bs)); } return set; } /** * 获取所有的value */ @Override public Collection values() { Set keys = this.keys(); List<Object> values = new ArrayList<Object>(); for (Object key : keys) { byte[] bytes = JedisClientSingle.getJedis().get(getByteKey(key)); values.add(ByteSourceUtils.deserialize(bytes)); } return values; }}
创建CustomCacheManager实现CacheManager接口
package com.why.authority.cache;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.apache.shiro.cache.CacheManager;/** * @author: 王洪玉 * @decsription: 自定义缓存管理器 * @create: 2017/12/5 21:43 * @modified By: * */public class CustomCacheManager implements CacheManager { @Override public <K, V> Cache<K, V> getCache(String name) throws CacheException { return new RedisCache<K,V>(); }}
Jedis工具类JedisClientSingle
package com.why.utils.jedis;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;/** * 单机版 * @author why * @Time 2017年10月31日 */public class JedisClientSingle { private static JedisPool jedisPool; static { JedisPoolConfig jedisConfig = new JedisPoolConfig(); jedisConfig.setMaxTotal(100); jedisConfig.setMaxIdle(10); jedisConfig.setMaxWaitMillis(100); //主机名称和端口号,开启redis的服务器和端口号 jedisPool = new JedisPool(jedisConfig, "192.168.131.128", 6379); } public static Jedis getJedis() { return jedisPool.getResource(); } public static void close(Jedis jedis) { jedis.close(); }}
登录认证
由于在Spring-Shiro.xml文件中已经配置开启登录时开启缓存,那么当用户登录的时候,会默认先调用RedisCache的get方法从缓存中获取,如果没有该用户的缓存的话,则执行登录的业务查询数据库,然后将查询出来的数据存入到缓存中。
自定义Realm实现登录验证
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //1.把AuthenticationToken转换为UsernamePasswordToken UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token; //2.从UsernamePasswordToken中获取userCode String userCode = usernamePasswordToken.getUsername(); //3.获取用户信息userEntity List<UserEntity> userEntityList = userFacade.findByUserCode(userCode); UserEntity userEntity=userEntityList.get(0); //4.根据用户的情况,来构建AuthenticationInfo对象并返回 String credentials = userEntity.getPassword(); //使用ByteSource.Util.bytes()来计算盐值 //ByteSource credentialsSalt = ByteSource.Util.bytes(userCode); return new SimpleAuthenticationInfo(userEntity, credentials,new MySimpleByteSource(userCode),getName()); }
注意:这里最初用的是下面的代码,但是会报java.io.NotSerializableException:org.apache.shiro.util.SimpleByteSource异常,出现这个问题的原因就是在将用户信息存入Redis之前,需要将SimpleAuthenticationInfo信息进行序列化,但是SimpleByteSource没有是实现Serializable接口
解决办法:自定义一个类继承SimpleByteSource实现Serializable接口或实现ByteSource接口和Serializable接口,具体请看我的这篇博客:点击这里
ByteSource credentialsSalt = ByteSource.Util.bytes(userCode);return new SimpleAuthenticationInfo(userEntity, credentials,credentialsSalt,getName());
总结:到此为止,我们的Shiro的缓存管理器就成功的切换成Redis了,过程中学习到了很多,遇到了各种BUG,但是通过不断的调试和查资料,还是都解决了,看到功能成功实现,还是很开心的。
- [Shiro入门](一)使用Redis作为缓存管理器
- 使用redis作为缓存
- 使用redis作为缓存
- redisCacheManager(redis缓存管理器使用)
- 使用Redis作为LRU缓存
- 使用Redis作为LRU缓存
- 使用Redis作为缓存2
- 使用Redis作为LRU缓存
- 使用Redis作为LRU缓存
- REDIS学习(3.2)spring boot 使用redis作为缓存
- [Shiro入门] (二)缓存管理器SimpleByteSource序列化问题
- Redis作为MySQL缓存服务器的使用
- Redis实战(一) 使用缓存合理性
- Redis实战(一) 使用缓存合理性
- nodejs使用redis作为缓存介质,封装缓存类
- apache shiro 入门(一)
- Redis作为缓存总结
- Redis作为缓存
- A06_大文件拷贝
- hibernate关系映射管理(一对多,多对一,一对一,多对多)
- Oracle压缩黑科技(二)—压缩数据的修改
- 如何修改网卡名称由enp0s25为eth0 (by quqi99)
- 在Linux系统下源码安装node.js
- [Shiro入门](一)使用Redis作为缓存管理器
- 2017年12月银行卡跨行ATM取现手续费
- JAVA第一步工作 classpath、path、JAVA_HOME的作用及JAVA环境变量配置等
- IEnumerator和IEnumerable的区别
- R语言在ubuntu下的编译安装
- ubuntu安装nvidia, cuda和cudnn
- MVP封装成基类结合retrofit和Rxjava
- Django的 session与cookie
- java中代码 &0xFF是怎么个意思