好的网站优化公司,延津县建设局网站,wordpress更换icon,弄几个的网站springboot配置shiro多项目实现session共享的详细步骤
公司需要这样的需求#xff1a;
有两个项目master 主项目、suiteone 项目#xff0c;两个项目各自由shiro 安全框架管理#xff0c;当不能登录时#xff0c;都无法访问#xff0c;但当登录了其中一个#xff0c;再…springboot配置shiro多项目实现session共享的详细步骤
公司需要这样的需求
有两个项目master 主项目、suiteone 项目两个项目各自由shiro 安全框架管理当不能登录时都无法访问但当登录了其中一个再访问另一个的时候不再需要登录即可访问。 如果想看为什么需要共享session ,可以去看我这篇文章。[shiro框架—关于多项目之间验证为什么需要共享session]
关于实现多项目共享session的逻辑介绍
其实在上边的链接里我已经说明了但是怕大家不去看所以我就又复制到了这里 先来说一下我的理解 如下 上图中master 项目为主项目登录页即在这个项目中suiteone 、suitetwo 为两个从项目当两个从项目有请求时如果没有登录的时候都会打到master 项目的登录页上。共享session 采用的是redis 存储。
上图的步骤如下
浏览器请求master 项目第一次请求的时候也是会带着浏览器中的cookie 去请求当然第一次去redis 里肯定找不到对应的session会通过⑤进入到登录页。当在登录页输入完正确的账号密码后才能登录成功否则仍会回到⑤。在这一步的时候会将登录成功后的session 根据它将生成sessionId串 并传到前端浏览器中浏览器以cookie 存储。同时将第③步中生成的session 存储到redis 中。当前这里不只是当登录失败的时候会进入到登录页中当浏览器长时间没有访问后台每次浏览器访问后台其实都会刷新session 的过期时间expireTime导致session 超过时也会进入到该步中。当浏览器请求suiteone 、suteTwo 这两个从项目时肯定也是将当前浏览器中的所有的cookie 设置到request headers 请求头中。根据传入的sessionId串 到共享的redis 存储中匹配。如果匹配不到则会跳转到master 项目的登录页如果匹配成功则会访问通过。
以上描述的并不难大家也都会想到那么如何将扯了这么多的淡 真正更简单的落地实现才是大家关注的。
多项目通过redis共享session的步骤
1、shiro 共享session 的切入点下图是shiro的验证流程 2、配置过程
说一下实现shiro 项目共享session 的配置步骤
1项目多添加redis 依赖。
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-redis/artifactIdversion1.3.6.RELEASE/version/dependency2配置application.properties 文件
###主项目写成自己项目的登录页面路径从项目必须写完整的主项目登录页面url
shiro.loginUrl/login
###主从项目的下边名字必须一致
shiro.jessionidsessionId
###redis连接配置
spring.redis.host192.168.1.160
spring.redis.port6379
spring.redis.passwordznxd3重写session 增删改查与redis接入
package microservice.sc.shiro;import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;Service
public class RedisSessionDao extends AbstractSessionDAO {// Session超时时间单位为毫秒private long expireTime 120000;Autowiredprivate RedisTemplate redisTemplate;// Redis操作类对这个使用不熟悉的可以参考前面的博客public RedisSessionDao() {super();}public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {super();this.expireTime expireTime;this.redisTemplate redisTemplate;}Override // 更新sessionpublic void update(Session session) throws UnknownSessionException {System.out.println(update);if (session null || session.getId() null) {return;}session.setTimeout(expireTime);redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);}Override // 删除sessionpublic void delete(Session session) {System.out.println(delete);if (null session) {return;}redisTemplate.opsForValue().getOperations().delete(session.getId());}Override
// 获取活跃的session可以用来统计在线人数如果要实现这个功能可以在将session加入redis时指定一个session前缀统计的时候则使用keys(session-prefix*)的方式来模糊查找redis中所有的session集合public CollectionSession getActiveSessions() {System.out.println(getActiveSessions);return redisTemplate.keys(*);}Override// 加入sessionprotected Serializable doCreate(Session session) {System.out.println(doCreate);Serializable sessionId this.generateSessionId(session);this.assignSessionId(session, sessionId);redisTemplate.opsForValue().set(session.getId(), session, expireTime, TimeUnit.MILLISECONDS);return sessionId;}Override// 读取sessionprotected Session doReadSession(Serializable sessionId) {System.out.println(doReadSession);if (sessionId null) {return null;}return (Session) redisTemplate.opsForValue().get(sessionId);}public long getExpireTime() {return expireTime;}public void setExpireTime(long expireTime) {this.expireTime expireTime;}public RedisTemplate getRedisTemplate() {return redisTemplate;}public void setRedisTemplate(RedisTemplate redisTemplate) {this.redisTemplate redisTemplate;}
}
4将重写的RedisSessionDao 接入到shiro 中的sessionManager
Beanpublic RedisSessionDao getRedisSessionDao(){return new RedisSessionDao();}/*** see DefaultWebSessionManager* return*/Bean(namesessionManager)public DefaultWebSessionManager defaultWebSessionManager() {DefaultWebSessionManager sessionManager new DefaultWebSessionManager();//sessionManager.setCacheManager(cacheManager());sessionManager.setGlobalSessionTimeout(43200000); //12小时sessionManager.setDeleteInvalidSessions(true);//关键在这里sessionManager.setSessionDAO(getRedisSessionDao());sessionManager.setSessionValidationSchedulerEnabled(true);sessionManager.setDeleteInvalidSessions(true);sessionManager.setSessionIdCookie(getSessionIdCookie());return sessionManager;}5将sessionManager 注入到securityManager /*** see org.apache.shiro.mgt.SecurityManager* return*/Bean(namesecurityManager)public DefaultWebSecurityManager securityManager() {DefaultWebSecurityManager manager new DefaultWebSecurityManager();manager.setRealm(userRealm());//manager.setCacheManager(cacheManager());manager.setSessionManager(defaultWebSessionManager());return manager;}6设置登录页的地址 和cookie名字
首先引入我们刚才application.properties文件中的内容
Value(${shiro.loginUrl})
private String masterLoginUrl;Value(${shiro.jessionid})
private String jessionId;然后注入到配置中 Bean(name shiroFilter)public ShiroFilterFactoryBean shiroFilter(){ShiroFilterFactoryBean bean new MShiroFilterFactoryBean(); //指向自定义过滤器自定义过滤器对js/css等忽略bean.setSecurityManager(securityManager());//在这里设置登录页bean.setLoginUrl(masterLoginUrl);MapString, Filterfilters new LinkedHashMap();filters.put(anon, new AnonymousFilter());bean.setFilters(filters);//shiro配置过滤规则少量的话可以用hashMap,数量多了要用LinkedHashMap,保证有序原因未知MapString, String chains new LinkedHashMap();chains.put(/login,anon);chains.put(/loginForm,anon);chains.put(/**, authc);bean.setFilterChainDefinitionMap(chains);return bean;}/*** 给shiro的sessionId默认的JSSESSIONID名字改掉* return*/Bean(namesessionIdCookie)public SimpleCookie getSessionIdCookie(){SimpleCookie simpleCookie new SimpleCookie(jessionId);return simpleCookie;}注意如果值注入不进来则看一下当前的shiro 配置文件里的LifecycleBeanPostProcessor 的注入是否为static 方法,如下
/*** 该类如果不设置为staticValue注解就无效原因未知* return*/Beanpublic static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}7测试
我的项目如下 如下图所示我们是springbootdubbozookeeper 的项目 分别启动30000端口 的主项目master 项目、300001端口的从项目suiteone 项目启动后
首先访问主项目http://localhost:30000肯定进入登录页。当再访问http://localhost:30001/test 因为没有登录直接被重定向到http://localhost:30000 的登录页上即主项目的登录页。当在当前登录页上登录成功后再次访问http://localhost:30001/test 该接口即返回了数值。当我在主项目的http://localhost:30000中退出登录再次访问http://localhost:30001/test 同样重定向了登录页。应该能确定实现了session 共享。
具体如下图 登录页面在这时访问30001 也会进入下边这个页面 登录成功后 登录成功后访问30001的接口即可以访问成功
配置完成如有问题请及时留言。