如果单机,使用EHCache就可以的,单如果多节点部署时就不行了,本文主要将Shiro和Redis缓存集成,在上一篇文章Shiro功能应用(六)–登陆失败重试次数控制代码基础进行添加Redis缓存。 代码地址: 首先将ShiroConfig关于EHCache的和SessionManager的配置去掉。 ShiroConfig的安全管理器SecurityManager: ShiroConfig的Redis缓存管理器: ShiroConfig的Redis配置管理器: ShiroConfig的Redis会话管理器: ShiroConfig的redisSessionDao: 自定义Realm类修改认证方法返回的info: 新增的MySimpleByteSource类: 1).java.io.NotSerializableException: org.apache.shiro.util.SimpleByteSource异常: 因为认证方法返回info对象第三个参数ByteSource类型,并没有实现序列化接口,所以序列化的时候出现异常, 2).com.demo.entity.User cannot be cast to com.demo.entity.User转换异常: 3). org.crazycake.shiro.exception.PrincipalInstanceException: class com.demo.entity.User must has getter for field: authCacheKey or id无法获取缓存中权限redisKey。 解决: 也行换个包可以解决,要么就修改User类,但改动会有点大,要么就换一种Redis的实现方式,也就是不用Shiro-Redis的包。可查看下一篇Shiro功能应用(八)–Shiro集成RedisTemplate(SDR) 4).RedisCache才是主要操作redis缓存的操作类, 代码中任何出现操作缓存(get、put)之类的,都会到这个类操作代码实现:
https://github.com/OooooOz/SpringBoot-Shiro @Bean(name="securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("shiroRealm") MyShiroRealm shiroRealm){ ... ... ... ... securityManager.setCacheManager(redisCacheManager()); //配置 redis缓存管理器 securityManager.setSessionManager(redisSessionManager()); //配置 redissession管理 return securityManager; }
//import org.crazycake.shiro.RedisCacheManager;包的RedisCacheManager的对象 @Bean("redisCacheManager") public RedisCacheManager redisCacheManager(){ RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; }
@Bean public RedisManager redisManager(){ RedisManager redisManager = new RedisManager(); redisManager.setHost("192.168.2.104"); redisManager.setPort(6379); //redisManager.setPassword("123456"); return redisManager; }
@Bean("redisSessionManager") public SessionManager redisSessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); Collection<SessionListener> listeners = new ArrayList<SessionListener>(); //配置监听 listeners.add(sessionListener()); sessionManager.setSessionListeners(listeners); sessionManager.setSessionIdCookie(sessionIdCookie()); sessionManager.setSessionDAO(redisSessionDAO()); sessionManager.setCacheManager(redisCacheManager()); //sessionManager.setGlobalSessionTimeout(60000); //全局会话超时时间(单位毫秒),默认30分钟 暂时设置为10秒钟 用来测试 sessionManager.setDeleteInvalidSessions(true); //取消url 后面的 JSESSIONID sessionManager.setSessionIdUrlRewritingEnabled(false); return sessionManager; }
@Bean("redisSessionDAO") public SessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); redisSessionDAO.setExpire(3000);//session在redis中的保存时间,最好大于session会话超时时间,单位s return redisSessionDAO; }
SimpleAuthenticationInfo authenticationInfo = // new SimpleAuthenticationInfo(user,user.getPassword(),ByteSource.Util.bytes(user.getSalt()),"shiroRealm"); new SimpleAuthenticationInfo(user,user.getPassword(),new MySimpleByteSource(user.getSalt()),"shiroRealm");
/** * 解决: * shiro 使用缓存时出现:java.io.NotSerializableException: org.apache.shiro.util.SimpleByteSource * 序列化后,无法反序列化的问题 */ public class MySimpleByteSource implements ByteSource, Serializable { private static final long serialVersionUID = 5175082362119580768L; private byte[] bytes; private String cachedHex; private String cachedBase64; public MySimpleByteSource(){ } public MySimpleByteSource(byte[] bytes) { this.bytes = bytes; } public MySimpleByteSource(char[] chars) { this.bytes = CodecSupport.toBytes(chars); } public MySimpleByteSource(String string) { this.bytes = CodecSupport.toBytes(string); } public MySimpleByteSource(ByteSource source) { this.bytes = source.getBytes(); } public MySimpleByteSource(File file) { this.bytes = (new BytesHelper()).getBytes(file); } public MySimpleByteSource(InputStream stream) { this.bytes = (new BytesHelper()).getBytes(stream); } public static boolean isCompatible(Object o) { return o instanceof byte[] || o instanceof char[] || o instanceof String || o instanceof ByteSource || o instanceof File || o instanceof InputStream; } public void setBytes(byte[] bytes) { this.bytes = bytes; } @Override public byte[] getBytes() { return this.bytes; } @Override public String toHex() { if(this.cachedHex == null) { this.cachedHex = Hex.encodeToString(this.getBytes()); } return this.cachedHex; } @Override public String toBase64() { if(this.cachedBase64 == null) { this.cachedBase64 = Base64.encodeToString(this.getBytes()); } return this.cachedBase64; } @Override public boolean isEmpty() { return this.bytes == null || this.bytes.length == 0; } @Override public String toString() { return this.toBase64(); } @Override public int hashCode() { return this.bytes != null && this.bytes.length != 0? Arrays.hashCode(this.bytes):0; } @Override public boolean equals(Object o) { if(o == this) { return true; } else if(o instanceof ByteSource) { ByteSource bs = (ByteSource)o; return Arrays.equals(this.getBytes(), bs.getBytes()); } else { return false; } } private static final class BytesHelper extends CodecSupport { private BytesHelper() { } public byte[] getBytes(File file) { return this.toBytes(file); } public byte[] getBytes(InputStream stream) { return this.toBytes(stream); } }
主要问题:
解决: 自定义一个类实现ByteSource和Serializable接口,见上文MySimpleByteSource
一看,同样类型为什么转换不成呢?因为SpringBoot项目配了热部署。
解决: 注释掉热部署依赖。Clear一下就好了。<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <scope>true</scope> </dependency>
因为shiro-redis3.1.0里面,有个条件写死的。本人的User类不满足条件。
可见,User类要有AuthCacheKey或者Id属性,也就是要有getAuthCacheKey()或getId()方法,条件才能满足,下面会通过映射获取属性值。不满足就抛异常了。
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算