spring boot shiro redis整合

spring boot redis整合spring boot redis整合

spring boot shiro整合  spring boot shiro整合

在上篇整合shiro 的基础上 shiroConfig配置修改如下 红色部分为新增,整合中从redis中获取session时出现类型转换错误在本文结尾有说明及解决方法

需要注意的是我这里的实现 是session实现了redis缓存管理,但是其他的缓存还是存放在ehcache里,以后有时间会写把其他的缓存数据也放到redis 的文章

package com.zyc.springboot.config;import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.Filter;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.filter.DelegatingFilterProxy;import com.zyc.springboot.shiro.MyFormAuthenticationFilter;
import com.zyc.springboot.shiro.MyRealm;
import com.zyc.springboot.shiro.MyShiroSessionListener;
import com.zyc.springboot.shiro.RedisUtil;
import com.zyc.springboot.shiro.SessionDao;@Configuration
public class ShiroConfig {@Bean(name = "shiroEhcacheManager")public EhCacheManager getEhCacheManager() {EhCacheManager em = new EhCacheManager();em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");return em;}@Bean(name = "lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {LifecycleBeanPostProcessor lifecycleBeanPostProcessor = new LifecycleBeanPostProcessor();return lifecycleBeanPostProcessor;}@Bean(name = "sessionValidationScheduler")public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler() {ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler();scheduler.setInterval(900000);//scheduler.setSessionManager(defaultWebSessionManager());return scheduler;}@Beanpublic HashedCredentialsMatcher hashedCredentialsMatcher() {HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;hashedCredentialsMatcher.setHashIterations(1);// 散列的次数,比如散列两次,相当于md5(md5(""));return hashedCredentialsMatcher;}@Bean(name = "defaultWebSecurityManager")public DefaultWebSecurityManager defaultWebSecurityManager(MyRealm myRealm,DefaultWebSessionManager defaultWebSessionManager) {DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();defaultWebSecurityManager.setRealm(myRealm);defaultWebSecurityManager.setCacheManager(getEhCacheManager());defaultWebSecurityManager.setSessionManager(defaultWebSessionManager);defaultWebSecurityManager.setRememberMeManager(rememberMeManager());return defaultWebSecurityManager;}@Bean(name = "rememberMeCookie")public SimpleCookie rememberMeCookie() {// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMeSimpleCookie simpleCookie = new SimpleCookie("rememberMe");// simpleCookie.setMaxAge(259200);return simpleCookie;}/*** cookie管理对象;* * @return*/@Bean(name = "rememberMeManager")public CookieRememberMeManager rememberMeManager() {CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());return cookieRememberMeManager;}@Bean@DependsOn(value = "lifecycleBeanPostProcessor")public MyRealm myRealm() {MyRealm myRealm = new MyRealm();myRealm.setCacheManager(getEhCacheManager());myRealm.setCredentialsMatcher(hashedCredentialsMatcher());return myRealm;}@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getAutoProxyCreator(){DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();creator.setProxyTargetClass(true);return creator;}@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(DefaultWebSecurityManager defaultWebSecurityManager) {AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();aasa.setSecurityManager(defaultWebSecurityManager);return aasa;}@Bean(name = "sessionManager")public DefaultWebSessionManager defaultWebSessionManager(SessionDao sessionDao) {DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setGlobalSessionTimeout(18000000);
//		//url中是否显示session IdsessionManager.setSessionIdUrlRewritingEnabled(false);
//		// 删除失效的sessionsessionManager.setDeleteInvalidSessions(true);sessionManager.setSessionValidationSchedulerEnabled(true);sessionManager.setSessionValidationInterval(18000000);sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler());//设置SessionIdCookie 导致认证不成功,不从新设置新的cookie,从sessionManager获取sessionIdCookie//sessionManager.setSessionIdCookie(simpleIdCookie());sessionManager.getSessionIdCookie().setName("session-z-id");sessionManager.getSessionIdCookie().setPath("/");sessionManager.getSessionIdCookie().setMaxAge(60*60*24*7);sessionManager.setSessionDAO(sessionDao);Collection c=new ArrayList<>();c.add(new MyShiroSessionListener());sessionManager.setSessionListeners(c);return sessionManager;} @Beanpublic SessionDao sessionDao(RedisUtil redisUtil) {SessionDao sessionDao = new SessionDao();sessionDao.setRedisUtil(redisUtil);return sessionDao;}@Beanpublic RedisUtil redisUtil(RedisTemplate redisTemplate) {RedisUtil redisUtil = new RedisUtil();redisUtil.setRedisTemplate(redisTemplate);return redisUtil;}@Bean(name = "filterRegistrationBean1")public FilterRegistrationBean filterRegistrationBean() {FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilter"));filterRegistrationBean.addInitParameter("targetFilterLifecycle", "true");filterRegistrationBean.setEnabled(true);filterRegistrationBean.addUrlPatterns("/");return filterRegistrationBean;}@Bean(name = "shiroFilter")public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {// SecurityUtils.setSecurityManager(defaultWebSecurityManager);ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setLoginUrl("/login");shiroFilterFactoryBean.setSuccessUrl("/getMyJsp");shiroFilterFactoryBean.setUnauthorizedUrl("/login");shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);Map filterMap1 = shiroFilterFactoryBean.getFilters();filterMap1.put("authc", new MyFormAuthenticationFilter());shiroFilterFactoryBean.setFilters(filterMap1);Map filterMap = new LinkedHashMap();filterMap.put("/static/**", "anon");filterMap.put("/logout", "logout");filterMap.put("/login", "authc");filterMap.put("/**", "authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);return shiroFilterFactoryBean;}}

sessionDao 需要自己添加继承EnterpriseCacheSessionDAO:

package com.zyc.springboot.shiro;import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;public class SessionDao extends EnterpriseCacheSessionDAO {private RedisUtil redisUtil;public RedisUtil getRedisUtil() {return redisUtil;}public void setRedisUtil(RedisUtil redisUtil) {this.redisUtil = redisUtil;}// 创建session,保存到数据库@Overrideprotected Serializable doCreate(Session session) {Serializable sessionId = super.doCreate(session);redisUtil.set(sessionId.toString(), sessionToByte(session),1*60L);return sessionId;}// 获取session@Overrideprotected Session doReadSession(Serializable sessionId) {// 先从缓存中获取session,如果没有再去数据库中获取Session session = super.doReadSession(sessionId); if(session == null){byte[] bytes = (byte[]) redisUtil.get(sessionId.toString());if(bytes != null && bytes.length > 0){session = byteToSession(bytes);    }}return session;}// 更新session的最后一次访问时间@Overrideprotected void doUpdate(Session session) {super.doUpdate(session);redisUtil.set(session.getId().toString(), sessionToByte(session),1*60L);}// 删除session@Overrideprotected void doDelete(Session session) {super.doDelete(session);redisUtil.remove(session.getId().toString());}// 把session对象转化为byte保存到redis中public byte[] sessionToByte(Session session){ByteArrayOutputStream bo = new ByteArrayOutputStream();byte[] bytes = null;try {ObjectOutput oo = new ObjectOutputStream(bo);oo.writeObject(session);bytes = bo.toByteArray();} catch (IOException e) {e.printStackTrace();}return bytes;}// 把byte还原为sessionpublic Session byteToSession(byte[] bytes){ByteArrayInputStream bi = new ByteArrayInputStream(bytes);ObjectInputStream in;SimpleSession session = null;try {in = new ObjectInputStream(bi);session = (SimpleSession) in.readObject();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return session;}
}

ShiroSessionListener需要自己添加 如下:

package com.zyc.springboot.shiro;import org.apache.shiro.session.Session;
import org.apache.shiro.session.SessionListener;import com.zyc.springboot.util.SpringContext;public class MyShiroSessionListener implements SessionListener {@Overridepublic void onStart(Session session) {}@Overridepublic void onStop(Session session) {// TODO Auto-generated method stubSystem.out.println("onStop==="+session.getId());RedisUtil redisUtil=(RedisUtil) SpringContext.getBean("redisUtil");redisUtil.remove(session.getId().toString());}@Overridepublic void onExpiration(Session session) {System.out.println("onExpiration==="+session.getId());RedisUtil redisUtil=(RedisUtil) SpringContext.getBean("redisUtil");redisUtil.remove(session.getId().toString());}}

这里需要注意,redisUtil类需要在配置文件中使用@Bean配置,如果直接在RedisUtil类头部添加@Service注解 可能redisUtil会报空指针错误

如果从redis获取session时 无法把String类型转换成byte[] 类型,则修改RedisConfig中redisTemplate.setValueSerializer()为JdkSerializationRedisSerializer类型,本例中使用的是Jackson2JsonRedisSerializer

问题1:shiro 调用subject.logout();时返回登录界面,但是浏览器地址却不是登录地址,或者退出后后需要点击2次登录才能登录成功

解决:使用springmvc 时,在Controller 层写logout方法 返回地址 使用重定向 return "redirect:login" 代替 return "login";这里注意 你的shiro 配置中需要有 /logout=logout


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部