shiro使用reids缓存session 踩坑
方案一: shiro-redis插件[未成功
]
-
shiro整合redis出现java.lang.ClassNotFoundException: org.apache.shiro.event.EventBus异常
-
java.io.NotSerializableException
方案二: 修改sessionDao,手动实现存储读取 [成功
]
-
出现序列化问题: 创建有个新的redisTemplate,设置序列化为byte[]
-
-
成功实现存储和读取
-
不足: 不能在redis清除的看到存储的session信息
-
-
存储mybatis-generator生成的pojo对象无法序列化
- 给pojo生成时配置mybatis-genrerate插件使实现Serializable接口
-
MYBATIS GENERATOR系列(六)----MYBATIS GENERATOR PLUGIN插件之SERIALIZABLEPLUGIN
-
-
读取session,shiro多次调用redis读取session
shiro配置
@Configuration
public class ShiroConfig {
@Value("${spring.redis.shiro.host}")
private String host;
@Value("${spring.redis.shiro.port}")
private int port;
@Value("${spring.redis.shiro.timeout}")
private int timeout;
@Value("${spring.redis.shiro.password}")
private String password;
// 这个redisUtil是json格式的存储读取
@Resource
RedisUtil redisUtil;
// 这个是btye格式的存储和读取,由于session格式成json一直报序列化错误,只能存成byte
@Resource
RedisSessionUtil redisSessionUtil;
@Value(value = "${mcinema.auth.session-token-key}")
private String SESSION_TOKEN_KEY;
@Value(value = "${mcinema.redis-key.session-admin}")
private String sessionRoot;
// 注册shiroFilterFactoryBean
@Bean(name = "shiroFilterFactoryBean")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
Map<String, String> filter = new LinkedHashMap<>();
// 设置拦截器
bean.setFilterChainDefinitionMap(filter);
return bean;
}
//注册DefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager adminWebSecurityManager(
AdminRealm adminRealm,
AdminSessionManagement sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(adminRealm); // 设置Realm对象
securityManager.setSessionManager(sessionManager); // 设置session管理
return securityManager;
}
//注册Realm
@Bean(name = "adminRealm")
public AdminRealm adminRealm() {
return new AdminRealm();
}
// 注册sessionManager
@Bean(name = "sessionManager")
public AdminSessionManagement adminSessionManagement(AdminSessionDAO adminSessionDAO) {
AdminSessionManagement sessionManagement = new AdminSessionManagement(SESSION_TOKEN_KEY);
sessionManagement.setSessionDAO(adminSessionDAO);
return sessionManagement;
}
@Bean(name="adminSessionDAO")
public AdminSessionDAO adminSessionDAO(){
return new AdminSessionDAO(redisSessionUtil,sessionRoot);
}
// 开启注解功能
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
creator.setProxyTargetClass(true);
return creator;
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
return authorizationAttributeSourceAdvisor;
}
}
redis template配置
@Bean(name = "redisSessionTemplate")
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisSessionTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
MyRedisSerializer myRedisSerializer = new MyRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setValueSerializer(myRedisSerializer);
template.setHashValueSerializer(myRedisSerializer);
template.setDefaultSerializer(myRedisSerializer);
template.afterPropertiesSet();
return template;
}
自定义序列化方式 这个更shiro-redis插件配置的ObjectSerialize差不多,不知道为什么我用那个还是会报错
public class MyRedisSerializer implements RedisSerializer<Object> {
@Override
public byte[] serialize(Object o) throws SerializationException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream objOut;
try {
objOut = new ObjectOutputStream(byteOut);
objOut.writeObject(o);
} catch (IOException e) {
e.printStackTrace();
}
return byteOut.toByteArray();
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
if(bytes == null) return null;
ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
ObjectInputStream objIn;
Object obj;
try {
objIn = new ObjectInputStream(byteIn);
obj =objIn.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
return obj;
}
}
redisUtil就不贴了,都差不多,你改下操作的template就行了
看运行发现读取次数过多,网上的办法是将获取的session存储到request里
自定义的sessionManager 继承 defaultSessionManage 覆写 retrieveSession方法
这个是网上抄的,水平有限,就没改了,能用就行,发现问题评论告诉我
public class AdminSessionManagement extends DefaultWebSessionManager{
@Override
protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
Serializable sessionId = getSessionId(sessionKey);
if (sessionId == null) {
log.debug("Unable to resolve session ID from SessionKey [{}]. Returning null to indicate a "
+ "session could not be found.", sessionKey);
return null;
}
// ***************Add By Goma****************
ServletRequest request = null;
if (sessionKey instanceof WebSessionKey) {
request = ((WebSessionKey) sessionKey).getServletRequest();
}
if (request != null) {
Object s = request.getAttribute(sessionId.toString());
if (s != null) {
return (Session) s;
}
}
// ***************Add By Goma****************
Session s = retrieveSessionFromDataSource(sessionId);
if (s == null) {
// session ID was provided, meaning one is expected to be found, but
// we couldn't find one:
String msg = "Could not find session with ID [" + sessionId + "]";
throw new UnknownSessionException(msg);
}
// ***************Add By Goma****************
if (request != null) {
request.setAttribute(sessionId.toString(), s);
}
// ***************Add By Goma****************
return s;
}
// session的键值
private final String SESSION_TOKEN_KEY;
// session的来源
private static final String SESSION_SOURCE = "request header";
public AdminSessionManagement(String session_token_key) {
this.SESSION_TOKEN_KEY = session_token_key;
}
@Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
String id = WebUtils.toHttp(request).getHeader(SESSION_TOKEN_KEY);
if (DataUtil.checkEmpty(id)) {
WebUtils.toHttp(response).setHeader(SESSION_TOKEN_KEY, id);
// 设置session来源
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, SESSION_SOURCE);
// 设置sessionId
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
// 设置标记此sessionId为有效
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return id;
}
return super.getSessionId(request, response);
}
}