精华内容
下载资源
问答
  • shiro框架---多项目登录访问共享session的实现

    万次阅读 多人点赞 2018-08-04 17:55:57
    shiro框架—多项目登录访问共享session的实现 公司需要这样的需求:   有两个项目master 主项目、suiteone 项目,两个项目各自由shiro 安全框架管理,当不能登录时,都无法访问,但当登录了其中一个,再访问另...

    shiro框架—多项目登录访问共享session的实现

    公司需要这样的需求:

      有两个项目master 主项目、suiteone 项目,两个项目各自由shiro 安全框架管理,当不能登录时,都无法访问,但当登录了其中一个,再访问另一个的时候不再需要登录即可访问。
      如果想看为什么需要共享session ,可以去看我这篇文章。shiro框架—关于多项目之间验证为什么需要共享session

    关于实现多项目共享session的逻辑介绍

      其实在上边的链接里我已经说明了,但是怕大家不去看,所以我就又复制到了这里:
    先来说一下我的理解 ,如下:

    这里写图片描述
      上图中master 项目为主项目,登录页即在这个项目中,suiteonesuitetwo 为两个从项目,当两个从项目有请求时,如果没有登录的时候,都会打到master 项目的登录页上。共享session 采用的是redis 存储。

    上图的步骤如下:

    1. 浏览器请求master 项目,第一次请求的时候,也是会带着浏览器中的cookie 去请求,当然第一次去redis 里肯定找不到对应的session,会通过⑤进入到登录页。
    2. 当在登录页输入完正确的账号密码后,才能登录成功,否则仍会回到⑤。
    3. 在这一步的时候,会将登录成功后的session ,根据它,将生成sessionId串 ,并传到前端浏览器中,浏览器以cookie 存储。
    4. 同时将第③步中生成的session 存储到redis 中。
    5. 当前这里,不只是当登录失败的时候,会进入到登录页中,当浏览器长时间没有访问后台(每次浏览器访问后台,其实都会刷新session 的过期时间expireTime),导致session 超过时,也会进入到该步中。
    6. 当浏览器请求suiteonesuteTwo 这两个从项目时,肯定也是将当前浏览器中的所有的cookie 设置到request headers 请求头中。
    7. 根据传入的sessionId串 到共享的redis 存储中匹配。
    8. 如果匹配不到,则会跳转到master 项目的登录页,如果匹配成功,则会访问通过。

      以上描述的并不难,大家也都会想到,那么如何将扯了这么多的淡 真正更简单的,落地实现才是大家关注的。

    多项目通过redis共享session的步骤

      关于该项目已在GitHub上传,有兴趣的可以下载下来瞧瞧,GitHub项目地址

    1、shiro 共享session 的切入点,下图是shiro的验证流程

    这里写图片描述

    2、配置过程

      说一下实现shiro 项目共享session 的配置步骤:

    (1)项目多添加redis 依赖。
    <dependency>
        <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-redis</artifactId>
         <version>1.3.6.RELEASE</version>
     </dependency>
    
    (2)配置application.properties 文件
    ###主项目写成自己项目的登录页面路径,从项目必须写完整的主项目登录页面url
    shiro.loginUrl=/login
    ###主从项目的下边名字必须一致
    shiro.jessionid=sessionId
    ###redis连接配置
    spring.redis.host=192.168.1.160
    spring.redis.port=6379
    spring.redis.password=znxd
    
    (3)重写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;
    
    /**
     * Created by Administrator on 2018/7/31.
     */
    @Service
    public class RedisSessionDao extends AbstractSessionDAO {
        // Session超时时间,单位为毫秒
        private long expireTime = 120000;
    
        @Autowired
        private RedisTemplate redisTemplate;// Redis操作类,对这个使用不熟悉的,可以参考前面的博客
    
        public RedisSessionDao() {
            super();
        }
    
        public RedisSessionDao(long expireTime, RedisTemplate redisTemplate) {
            super();
            this.expireTime = expireTime;
            this.redisTemplate = redisTemplate;
        }
    
        @Override // 更新session
        public 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 // 删除session
        public 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 Collection<Session> getActiveSessions() {
            System.out.println("==============getActiveSessions=================");
            return redisTemplate.keys("*");
        }
    
        @Override// 加入session
        protected 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// 读取session
        protected 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
    @Bean
    	public RedisSessionDao getRedisSessionDao(){
    		return new RedisSessionDao();
    	}
    	/**
    	 * @see DefaultWebSessionManager
    	 * @return
    	 */
    	@Bean(name="sessionManager")
    	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(name="securityManager")
    	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);
    		Map<String, Filter>filters = new LinkedHashMap<>();
    		filters.put("anon", new AnonymousFilter());
    		bean.setFilters(filters);
    		//shiro配置过滤规则少量的话可以用hashMap,数量多了要用LinkedHashMap,保证有序,原因未知
    		Map<String, 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(name="sessionIdCookie")
    	public SimpleCookie getSessionIdCookie(){
    		SimpleCookie simpleCookie = new SimpleCookie(jessionId);
    		return simpleCookie;
    	}
    

      注意,如果值注入不进来,则看一下当前的shiro 配置文件里的LifecycleBeanPostProcessor 的注入是否为static 方法,如下:

    /**
    	 * 该类如果不设置为static,@Value注解就无效,原因未知
    	 * @return
    	 */
    	@Bean
    	public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
    		return new LifecycleBeanPostProcessor();
    	}
    
    (7)测试

      我的项目如下:
      如下图所示,我们是springboot+dubbo+zookeeper 的项目:
    这里写图片描述
    分别启动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的接口,即可以访问成功
    这里写图片描述

    配置完成,如有问题请及时留言。

    展开全文
  • 实现session共享的三种方式发布时间:2020-06-05 16:16:43来源:亿速云阅读:341作者:Leah这篇文章为大家带来有关实现session共享的三种方式详细介绍。大部分知识点都是大家经常用到,为此分享给大家做个参考。...

    实现session共享的三种方式

    发布时间:2020-06-05 16:16:43

    来源:亿速云

    阅读:341

    作者:Leah

    这篇文章为大家带来有关实现session共享的三种方式的详细介绍。大部分知识点都是大家经常用到的,为此分享给大家做个参考。一起跟随小编过来看看吧。

    1.tomcat的session共享

    优点:不需要额外开发,只需搭建tomcat集群即可

    缺点:tomcat 是全局session复制,集群内每个tomcat的session完全同步保存着全部的session, 在大规模应用的时候,用户过多,集群内tomcat数量过多,session的全局复制会导致集群性能下降, 因此,tomcat的数量不能太多,而且依赖tomcat容器移植性不好(所以不采用)

    2.用cookie同步session

    这种完全把客户的登陆信息保存在客户端的cookie中,每次请求带着cookie中的Token

    优点:由于完全舍弃了session 会减轻服务器端的压力。

    缺点:是把信息暴露在外,就算有加密算法还是存在安全问题。禁止使用cookie的情况下无效。

    3.redis 集中管理session(常用的方式)

    优点:redis为内存数据库,读写效率高,并可在集群环境下做高可用, 项目案例 www.1b23.com

    下面就介绍下第三种的实现方式 spring boot 整合 redis session 做的session共享

    一、加入依赖

    Xml代码

    org.springframework.boot

    spring-boot-starter-data-redis

    org.springframework.session

    spring-session-data-redis

    二、yml文件

    Yml代码server:

    port: 8080

    spring:

    application:

    name: test-session

    redis:

    password: 12345678

    database: 0

    host: 127.0.0.1

    port: 6379

    三 启动类加入 @EnableRedisHttpSession

    Java代码importorg.springframework.boot.SpringApplication;

    importorg.springframework.boot.autoconfigure.SpringBootApplication;

    importorg.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

    importorg.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

    @EnableEurekaServer

    @SpringBootApplication

    @EnableRedisHttpSession

    publicclassEurekaServerApplication {

    publicstaticvoidmain(String[] args) {

    SpringApplication.run(EurekaServerApplication.class, args);

    }

    }

    以上就是实现session共享的三种方式的详细介绍,详细使用情况还需要大家自己亲自动手使用过才能领会。如果想了解更多相关内容,欢迎关注亿速云行业资讯频道!

    展开全文
  • 完美实现分布式集群Session共享 简单多tomcat8+redis的session共享实现,支持tomcat8、tomcat8.5、tomcat9,不能用直接联系我积分双倍返回。
  • PHP通过session id 实现session共享和登录验证代码,需要朋友可以参考下
  • 主要介绍了实现Asp与Asp.Net共享Session的方法,需要的朋友可以参考下
  • 主要介绍了thinkPHP多域名情况下使用memcache方式共享session数据的实现方法,较为详细的分析了session的原理及多服务器共享session的相关技巧,需要的朋友可以参考下
  • 小型web服务, session数据基本是保存在本地(更多是本地磁盘文件), 但是当部署多台服务, 且需要共享session, 确保每个服务都能共享到同一份session数据. redis 数据存储在内存中, 性能好, 配合持久化可确保数据完整. ...
  • 在使用spring boot做负载均衡时候,多个app之间的session要保持一致,这样负载到不同app时候,在一个app登录之后,而访问到另外一台服务器时候,session丢失。 常规解决方案都是使用:如apache使用mod_jk....

    在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外一台服务器的时候,session丢失。

    常规的解决方案都是使用:如apache使用mod_jk.conf,使用Memcached进行共享

        在开发spring boot app的时候可以借助 spring session 和redis或者ehcache,用外置的redis或者ehcache来存储session的状态,这里使用redis进行介绍,ehcache实现是一样的。

    增加相关依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-redis</artifactId>
        </dependency>
      
      <dependency>
          <groupId>org.springframework.session</groupId>
          <artifactId>spring-session-data-redis</artifactId>
    </dependency>


    RedisSessionConfig.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    package com.wisely.base;
      
    import org.springframework.context.annotation.Configuration;
    import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
      
    @Configuration
    @EnableRedisHttpSession
    public class RedisSessionConfig {
      
    }

    如果需要添加失效时间可以使用以下的写法:

    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60) //1分钟失效

    相关配置修改

    在application.properties修改redis配置信息(请自行安装redis),请根据实际修改。如:

    spring.redis.host=127.0.0.1

     所有实体类实现Serializable接口

    public class UserInfo implements Serializable

     查看效果

    这时候登录系统在不同的app之间跳转的时候,session都是一致了,redis上可以看到:


    总结

    使用这些代码之后 ,无论你使用nginx或者apache,都无须在关心多个app之间的session一致的问题了。


    注意事项

    (1)redis版本号需要是2.8以上否则会抛异常:ERR Unsupported CONFIG parameter: notify-keyspace-events;

    (2)RedisSessionConfig需要放在App.java启动类可以扫描的位置;

    展开全文
  • 主要介绍了SpringBoot Session共享实现图解,文中通过示例代码介绍非常详细,对大家学习或者工作具有一定参考学习价值,需要朋友可以参考下
  • 主要介绍了Zend Framework实现多服务器共享SESSION数据方法,详细分析了SESSION数据共享原理与实现技巧,需要朋友可以参考下
  • 其中最重要就是 设置session id 至 本地 cookies 当中, 采用如下方法:   $currentSessionID = session_id();   和   session_id($currentSessionID );     简单实例:   Script 1(HTTP) ...

    在网上找了很多,终于搞明白了,也行不是最好的办法,但确实非常使用的方法。

     

    其中最重要的就是 设置session id 至 本地 cookies 当中, 采用如下方法:

     

    $currentSessionID = session_id();
     

     

    session_id($currentSessionID );

     

     

    简单实例:

     

    Script 1(HTTP) :

     

    <?php
    
    // This script will create a session and display a link to your secure server address
    // to transfer your session ID. In this example, the secure page to receive the session
    // ID is located at http://www.yoursite.com/safePages/securePage.php
    
    // Start a session using the current session ID stored in a cookie, or create
    // a new session if none is set.
    
    session_start();
    
    $currentSessionID = session_id();
    
    // Set a variable that will be retrieved with the HTTPS script.
    $_SESSION['testvariable'] = 'It worked';
    
    // $secureServerDomain is the domain of your secure server
    $secureServerDomain = 'www.yoursite.com';
    
    // $securePagePath is the path to the page that will receive and set the session ID.
    $securePagePath = '/safePages/securePage.php'
    
    echo '<a href="https://' . $secureServerDomain . $securePagePath . '?session="' . $currentSessionID . '">Click here to transfer your session to the secure server</a>';
    
    ?>
    
     

    Script 2(HTTPS) :

     

    <?php
    
    // Retrieve the session ID as passed via the GET method.
    $currentSessionID = $_GET['session'];
    
    // Set a cookie for the session ID.
    session_id($currentSessionID);
    
    // Start a session.
    session_start();
    
    // Test retrieval of variable set when using HTTP.
    if (!empty($_SESSION['testvariable'])) {
          echo $_SESSION['testvariable'];
    } else {
          echo 'It did not work.';
    }
    
    ?>
    
     

     

    但是要注意的是:

    http://www.mysite.com/page.php   跳转到 https://www.mysite.com/page.php

    或者

    http://mysite.com 跳转到 https://mysite.com/page.php.

     

    关于安全性:

     

    应该讲和传统的登录验证安全性一样。都是不太安全的。因为sid的传输是没有加密的,别人也可以通过监听,嗅探来获取这个session id,也就获取了你的session数据。因此后面可以考虑将session id信息加密之后进行传输。

     

     

    另一种就是采用数据库的方式:

     

    见附件。

     

     

    require_once "session.class.php";
    $oSession = new Session();
    print_r($_SESSION); // First
    $_SESSION['hi'] = "lisha"; // Comment this Once sessoin is set
    $_SESSION['test'] = "gideon"; // Comment this Once sessoin is set
    
    echo '===========';
    //Now use php sessions as usual
    print_r($_SESSION); // First
     

     

    说明一下的是,需要用到 session_set_save_handler 函数,它要配合 ini_set('session.save_handler', 'user'); 一起使用!

     

     

     

     

    展开全文
  • 用PHP实现多服务器共享SESSION数据方法
  • 本篇开始学习Spring-Session相关一些知识学习整理,让我们开始吧!Spring-Session介绍Spring-Session使用场景?HttpSession是通过Servlet容器进行创建和管理,在单机环境中。通过Http请求创建的Session信息是...
  • 自己亲自试验,亲测有效。实现父子网站共享session。可实现单点登录的效果,具体还是发挥各位大佬的才能了,此文只是实现共享session的亲测案例
  • 基于Redis ClusterTomat的Session共享实现
  • 各个服务器共享用户数据是比较容易实现的,只需要在后端放个数据库服务器,各个服务器通过统一接口对用户数据进行访问即可。但还存在一个问题,就是用户在这个服务器登录之后,进入另一个服务器模块时,仍...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,666
精华内容 1,866
关键字:

共享session的实现