当前位置: 首页 > wzjs >正文

吉林建设工程信息网站网站服务器信息查询

吉林建设工程信息网站,网站服务器信息查询,国外化工网站模板,南山做网站推广乐云seo一、Shiro对Session 的处理 1、Shiro认证成功后是否还依赖Web容器的Session? 在Shiro 与Web(如:SSM、springboot)环境中,Shiro 认证成功后默认使用的是Web容器 的Session,并默认将Session保存到类 HttpSer…

一、Shiro对Session 的处理

1、Shiro认证成功后是否还依赖Web容器的Session?

      在Shiro 与Web(如:SSM、springboot)环境中,Shiro 认证成功后默认使用的是Web容器

      的Session,并默认将Session保存到类 HttpServletSession 中的 HttpSession 属性中;

      下边以源码的角度看下默认情况下Shiro对Session的处理:

       1)打开Springboot默认装载Shiro配置的类 ShiroWebAutoConfiguration

            ShiroWebAutoConfiguration位于shiro-spring-boot-web-starter 包下的文件 spring.factores

            中;在 ShiroWebAutoConfiguration 中我们找到Session 相关的2个核心配置 SessionDAO

            与 SessionManager,如下图所示:

                

        2)点开 sessionManager() 方法

              在 sessionManager() 方法中可以看到,首先会先判断当前环境是否配置了 

              “shiro.userNativeSessionManager” ?

               I)配置了该属性:则使用Shiro自身的Session管理器 DefaultWebSessionManager,

                    来处理Session

               II)没有配置该属性:默认情况,则使用Web容器相关的Session管理器

                     ServletContainerSessionManager

               如下图所示:

                    

                    

        3)ServletContainerSessionManager

              ServletContainerSessionManager 是基于Web容器的Session 管理器,主要用于

              获取Http请求中的Session和来源host,然后将Session和Host 封装成HttpServletSession

              如下图所示:

                     

                     

        4)nativefSessionManager() 方法

              该方法主要是创建Shiro 自身的Session管理器 DefaultWebSessionManager,并给

              SessionManager 设置 SessionDAO;如下图所示:

                  

        5)SessionDAO

             Shiro中 SessionDAO 到主要是用来处理Session 存储的问题;

             SessionDAO 的默认实现是 MemorySessionDAO,是一个基于内存的存储,即

             MemorySessionDAO 将Session 信息存储到一个全局的Map 中,

             注意:默认情况下 MemorySessionDAO 没有被使用,Shiro 将Session 保存到了

                        Web容器的 HttpSession 中

             如下图所示:

                   

                   

                   

二、Shiro对Session 缓存的支持

       由上边可以知道,默认情况下Shiro是将Session 保存到了Web 容器的HttpSession 中,但通过

       自定义SessionManager 与 SessionDAO 可以将 Session 保存到JVM内存和一些缓存中间件

       中,如:将Session 保存到redis 中。

1、将 Session 保存到JVM内存中

      由上边知道,Shiro 默认提供了将Session 保存到 JVM内存中的SessionDAO实现类 

      MemorySessionDAO,但 Shiro 默认情况下并没有使用 MemorySessionDAO;

      所以我们只要把 MemorySessionDAO 手动注入到 SessionManager 中就可以将Session

      保存到JVM内存中。

      实现方式:在Shiro配置类 ShiroConfig 中自定义 SessionManager,来覆盖默认情况下自动

                        装配的 SessionManager;并手动将 SessionDAO(默认是MemorySessionDAO )

                        注入到 SessionManager;最后将自定义的 SessionManager注入SecurityManager

       示例代码如下:

/*** 使用Shiro 提供的 MemorySessionDAO  将Session 保存到jvm内存中* @param sessionDAO* @return*/@Beanpublic SessionManager sessionManager(SessionDAO sessionDAO){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(sessionDAO);return sessionManager;}@Beanpublic DefaultWebSecurityManager securityManager(CustomRealm realm, SessionManager sessionManager){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);//将使用MemorySessionDAO的SessionManager注入到SecurityManagersecurityManager.setSessionManager(sessionManager);return securityManager;}

2、将 Session 保存到Redis 中

      将Session保存在jvm内存的情况只适合单机的架构中;在分布式环境中可以将Session单独存

      放到大家都可以访问的地方,如Redis,这样就可以解决分布式环境下Session共享的问题。

      由上边可以知道Session的存储具体是由SessionDAO完成的,所以我们需要模仿

      MemorySessionDAO 来定义一个基于Redis的 SessionDAO 的实现,来完成 Session 存储

     到Redis的操作,具体步骤如下:

     1)定义基于Redis 的 SessionDAO

           自定义 SessionDAO 需要继承抽象类 AbstractSessionDAO,并重写增加、修改、读取、

           删除Session 的方法,具体代码如下:

/***************************************************** 自定义 SessionDAO,用于将Session 存储到Redis* 让 SessionDAO 与 Redis 交互** 将 自定义的 SessionDAO 交由SessionManager 管理** @author lbf* @date ****************************************************/
@Component
public class RedisSessionDAO extends AbstractSessionDAO {// 存储到Redis时,sessionId作为key,Session作为Value// sessionId就是一个字符串// Session可以和sessionId绑定到一起,绑定之后,可以基于Session拿到sessionId// 需要给Key设置一个统一的前缀,这样才可以方便通过keys命令查看到所有关联的信息@Resourceprivate RedisTemplate redisTemplate;private final String SHIOR_SESSION = "session:";@Overrideprotected Serializable doCreate(Session session) {//1、生成SessionId,唯一标识Serializable sessionId = this.generateSessionId(session);//2、将SessionId 与 session 绑定一起,基于 sessionId可以拿到 sessionthis.assignSessionId(session,sessionId);//3. 将 前缀:sessionId 作为key,session作为value存储,并设置过期时间为30分钟redisTemplate.opsForValue().set(SHIOR_SESSION+sessionId,session,30, TimeUnit.MINUTES);//4、返回 sessionIdreturn sessionId;}@Overrideprotected Session doReadSession(Serializable sessionId) {//1. 基于sessionId获取Session (与Redis交互)if (sessionId == null) {return null;}Session session = (Session) redisTemplate.opsForValue().get(SHIOR_SESSION + sessionId);if (session != null) {//更新session超时时间redisTemplate.expire(SHIOR_SESSION + sessionId,30,TimeUnit.MINUTES);}return session;}@Overridepublic void update(Session session) throws UnknownSessionException {//1. 修改Redis中sessionif(session == null){return ;}//覆盖操作redisTemplate.opsForValue().set(SHIOR_SESSION + session.getId(),session,30, TimeUnit.MINUTES);}@Overridepublic void delete(Session session) {// 删除Redis中的Sessionif(session == null){return ;}redisTemplate.delete(SHIOR_SESSION + session.getId());}/*** 获取所有的Session* @return*/@Overridepublic Collection<Session> getActiveSessions() {//获取所有前缀为 session: 的key集合Set keys = redisTemplate.keys(SHIOR_SESSION + "*");Set<Session> sessionSet = new HashSet<>();// 尝试修改为管道操作,pipeline(Redis的知识)for (Object key : keys) {Session session = (Session) redisTemplate.opsForValue().get(key);sessionSet.add(session);}return sessionSet;}
}

        

     2)将自定义 SessionDAO 注入到 SessionManager

 @Beanpublic SessionManager sessionManager(RedisSessionDAO sessionDAO){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionDAO(sessionDAO);return sessionManager;}@Beanpublic DefaultWebSecurityManager securityManager(CustomRealm realm, SessionManager sessionManager){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);securityManager.setSessionManager(sessionManager);return securityManager;}

3、分析2 中的问题

     上边2的实现中有个问题,即:发现每次请求需要访问多次Redis服务,即使是同一个请求,

     每次也要从Redis 读取Session,这个访问的频次会出现很长时间的IO等待,对每次请求的

     性能减低了,并且对Redis的压力也提高了。

     通过debug 发现,系统是在 DefaultWebSessionManager.retrieveSession() 方法中调用

     SessionDAO的readSession() 方法去读取 Session 的,如下图所示:

           

     到这里应该有个大致思路了,我们可以自定义一个SessionManager,继承 

     DefaultWebSessionManager,并重写方法 retrieveSession,来重写读取Session

    的逻辑,即:先从HttpRequest 域 中获取Session,若获取不到再从Redis 中查询Session;

         示例代码如下:

/***************************************************** 自定义 WebSessionManager* 将传统的基于Web容器或者ConcurrentHashMap切换为Redis之后,发现每次请求需要访问多次Redis服务,这个访问的频次会出现很长时间的IO等待,* 对每次请求的性能减低了,并且对Redis的压力也提高了。** 基于装饰者模式重新声明SessionManager中提供的retrieveSession方法,让每次请求先去request域中查询session信息,request域中没有,再去Redis中查询** @author lbf* @date ****************************************************/
public class DefaultRedisWebSessionManager  extends DefaultWebSessionManager {private static final Logger log = LoggerFactory.getLogger(DefaultRedisWebSessionManager.class);@Overrideprotected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {// 通过sessionKey获取sessionIdSerializable sessionId = getSessionId(sessionKey);// 将sessionKey转为WebSessionKeyif(sessionKey instanceof WebSessionKey){WebSessionKey webSessionKey = (WebSessionKey) sessionKey;// 获取到request域ServletRequest request = webSessionKey.getServletRequest();// 通过request尝试获取session信息Session session = (Session) request.getAttribute(sessionId + "");if(session != null){System.out.println("从request域中获取session信息");return session;}else{session = retrieveSessionFromDataSource(sessionId);if (session == 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);}System.out.println("Redis---doReadSession");request.setAttribute(sessionId + "",session);return session;}}return null;}
}

   

       2)修改配置文件,使用自定义的 DefaultRedisWebSessionManager ,

/*** * 这里自定义 SessionManager 是为了 不使用基于Web 的Session,因为基于web的HttpSession 在分布式环境中是无法使用的** todo 注意:*     这里虽然将 SessionManager 注入到spring容器了,但自定义的 SessionManager 并没有生效,需要*     把自定义的 SessionManager 交给 SecurityManager 管理后才能生效**/@Beanpublic SessionManager sessionManager(RedisSessionDAO sessionDAO){//DefaultSessionManager sessionManager = new DefaultSessionManager();//使用自定义的SessionManagerDefaultRedisWebSessionManager sessionManager = new DefaultRedisWebSessionManager();sessionManager.setSessionDAO(sessionDAO);return sessionManager;}@Beanpublic DefaultWebSecurityManager securityManager(CustomRealm realm, SessionManager sessionManager){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);//将SessionManager注入到SecurityManagersecurityManager.setSessionManager(sessionManager);return securityManager;}

   


文章转载自:

http://VOg45xWR.ntqLz.cn
http://OzXOi2EU.ntqLz.cn
http://Xjx4MfyL.ntqLz.cn
http://9gGjg7jc.ntqLz.cn
http://9vEFnHNs.ntqLz.cn
http://NHzR1dQZ.ntqLz.cn
http://ZsLCeVo2.ntqLz.cn
http://plDRqMpf.ntqLz.cn
http://YBO4seX1.ntqLz.cn
http://feUaefoM.ntqLz.cn
http://rH7jq5hK.ntqLz.cn
http://zAw22Q72.ntqLz.cn
http://c2vw8PYk.ntqLz.cn
http://D8BQjmNb.ntqLz.cn
http://lsQWazlj.ntqLz.cn
http://DB88gUg0.ntqLz.cn
http://5gp8pmZO.ntqLz.cn
http://3tlChOJR.ntqLz.cn
http://pdxgANxa.ntqLz.cn
http://5IAUId4q.ntqLz.cn
http://6vsNq1dp.ntqLz.cn
http://ReLDqLuL.ntqLz.cn
http://r6I4a5fE.ntqLz.cn
http://xs7aH88v.ntqLz.cn
http://pIFq7qnW.ntqLz.cn
http://D2xskELt.ntqLz.cn
http://GAR4BWUH.ntqLz.cn
http://WMgyDgxl.ntqLz.cn
http://ukPwePZq.ntqLz.cn
http://YnhEZiuk.ntqLz.cn
http://www.dtcms.com/wzjs/702913.html

相关文章:

  • 网站开发需要会啥交通建设网站
  • 金融类网站建设wordpress怎么改登陆不了
  • 邢台好蜘蛛网站建设网站开店前的四项基本建设
  • wordpress 用js晨阳seo服务
  • 如何介绍设计的网站模板下载地址WordPress能做门户网吗
  • 江西东乡网站建设网站建设金手指专业
  • 购物网站建设名字wordpress 大数据插件
  • 优秀网站建设评选活动海报网络推广的定义
  • 网站免费正能量软件下载视频wordpress文章显示宽度
  • 揭东建设局网站免费网站服务器租用
  • 上海做公益活动有哪些好的网站南皮做网站的
  • 珠海网站建设公司网站建设合同技术开发合同范本
  • 网站做的文字乱码wordpress 菜单位置
  • 著名的个人网站去除wordpress评论电子邮件
  • 网站建设维护合同做网站时候编代码
  • 中贸网做的网站外贸代运营
  • 建c2c网站重庆网站页设计制作
  • 网站为什么被挂马wordpress插件中心
  • 网站落地页制作企业网站管理源码
  • 锡山建设局网站网上做兼职网站
  • 做境外碎片化旅游的网站门户类型的网站
  • 济南网站建设与优化投资公司注册条件及经营范围
  • 免费做封面网站网站制作包括什么
  • 东莞建站模板代理如何在大学网站做宣传
  • 企业网站建设平台福建网站建设模板
  • 网站建设与管理实训课程广州专业网站建设
  • 佛山外贸网站建设价位办公室装修效果图片大全
  • 网站开发可以当程序员湖南企业名录大全
  • 西城网站建设公司旅游网站建设模版
  • 名片在哪个网站做网站网址怎么写