shiro,自定义session,自定义sessionId

2019-09-28 00:00:25

既然都自定了session,还要自定义sessionId,都自定义到这种程度了,不如直接用jwt思想来做token了。

但是原来的项目已经有了,并且我想控制sessionId和session,来达到重启session不过期。

这些都自定义了,接下来加入缓存也就好了。

根据下面的文章,你可以读懂源码了,这样你在继承的类中,覆盖那些方法就好了。


参考资料  shiro源码篇 - shiro的session创建,你值得拥有


同样学习shiro的资料  《跟我学shiro》系列教程  我还没有读

  路漫漫其修远兮,吾将上下而求索!

  github:https://github.com/youzhibing

  码云(gitee):https://gitee.com/youzhibing

前情回顾

  大家还记得上篇博文讲了什么吗,我们来一起简单回顾下:

    HttpServletRequestWrapper是HttpServletRequest的装饰类,我们通过继承HttpServletRequestWrapper来实现我们自定义的HttpServletRequest:CustomizeSessionHttpServletRequest,重写CustomizeSessionHttpServletRequest的getSession,将其指向我们自定义的session。然后通过Filter将CustomizeSessionHttpServletRequest添加到Filter chain中,使得到达Servlet的ServletRequest是我们的CustomizeSessionHttpServletRequest。

  今天不讲session共享,我们先来看看shiro的session创建

SecurityManager

  SecurityManager,安全管理器;即所有与安全相关的操作都会与SecurityManager交互;它管理着所有Subject,所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;SecurityManager是shiro的核心,它负责与shiro的其他组件进行交互,类似SpringMVC中的DispatcherServlet或Struts2中的FilterDispatcher。

  我们在使用shiro的时候,首先都会先初始化SecurityManager,然后往SecurityManager中注入shiro的其他组件,像sessionManager、realm等。我们的spring-boot-shiro中初始化的是DefaultWebSecurityManager,如下

 View Code

  SecurityManager类图

    结构如下,认真看看,注意看下属性

    顶层组件SecurityManager直接继承了SessionManager且提供了SessionsSecurityManager实现,SessionsSecurityManager直接把会话管理委托给相应的SessionManager;SecurityManager的默认实现:DefaultSecurityManager及DefaultWebSecurityManager都继承了SessionsSecurityManager,也就是说:默认情况下,session的管理由DefaultSecurityManager或DefaultWebSecurityManager中的SessionManager来负责

    DefaultSecurityManager

      默认安全管理器,用于我们的javaSE安全管理,一般而言用到的少,但我们需要记住,万一哪次有这个需求呢。

      我们来看下他的构造方法

      默认的sessionManager是DefaultSessionManager,DefaultSessionManager具体详情请看下文。

    DefaultWebSecurityManager

      默认web安全管理器,用于我们的web安全管理;一般而言,我们的应用中初始化此安全管理器。

      我们来看看其构造方法

 View Code

      可以看出此时的sessionManager是ServletContainerSessionManager,ServletContainerSessionManager具体详情请看下文。

    由此可知默认情况下,DefaultSecurityManager会将session管理委托给DefaultSessionManager,而DefaultWebSecurityManager则将session管理委托给ServletContainerSessionManager。

    我们可以通过继承DefaultSecurityManager或DefaultWebSecurityManager来实现自定义SecurityManager,但一般而言没必要,DefaultSecurityManager和DefaultWebSecurityManager基本能满足我们的需要了,我们根据需求二选其一即可。无论DefaultSecurityManager还是DefaultWebSecurityManager,我们都可以通过setSessionManager方法来指定sessionManager,如果不指定sessionManager的话就用的SecurityManager默认的sessionManager。

SessionManager

  shiro提供了完整的会话管理功能,不依赖底层容器,JavaSE应用和JavaEE应用都可以使用。会话管理器管理着应用中所有Subject的会话,包括会话的创建、维护、删除、失效、验证等工作。

  SessionManager类图

      DefaultSessionManager

      DefaultSecurityManager默认使用的SessionManager,用于JavaSE环境的session管理。

      通过上图可知(结合SecurityManager类图),session创建的关键入口是SessionsSecurityManager的start方法,此方法中会将session的创建任务委托给具体的SessionManager实现。

      DefaultSessionManager继承自AbstractNativeSessionManager,没用重写start方法,所以此时AbstractNativeSessionManager的start方法会被调用,start方法如下

 View Code

      跟进createSession(),代码入下

 View Code

      其中doCreateSession方法完成session的创建,doCreateSession方法大家可以自行去跟下,我在这总结一下:       

        创建session,并生成sessionId,session是shiro的SimpleSession类型,sessionId采用的是随机的UUID字符串;
        sessionDAO类型是MemorySessionDAO,session存放在sessionDAO的private ConcurrentMap<Serializable, Session> sessions;属性中,key是sessionId,value是session对象;
        除了MemorySessionDAO,shiro还提供了EnterpriseCacheSessionDAO,具体两者有啥区别请看我的另一篇博客讲解。

    ServletContainerSessionManager

      DefaultWebSecurityManager默认使用的SessionManager,用于Web环境,直接使用的Servlet容器的会话,具体实现我们往下看。

      ServletContainerSessionManager实现了SessionManager,并重写了SessionManager的start方法,那么我们从ServletContainerSessionManager的start方法开始来看看session的创建过程,如下图

      shiro有自己的HttpServletSession,HttpServletSession持有servlet的HttpSession的引用,最终对HttpServletSession的操作都会委托给HttpSession(装饰模式)。那么此时的session是标准servlet容器支持的HttpSession实例,它不与Shiro的任何与会话相关的组件(如SessionManager,SecurityManager等)交互,完全由servlet容器管理。

    DefaultWebSessionManager

      用于Web环境,可以替换ServletContainerSessionManager,废弃了Servlet容器的会话管理;通过此可以实现我们自己的session管理;

      从SessionManager类图可知,DefaultWebSessionManager继承自DefaultSessionManager,也没有重写start方法,那么创建过程还是沿用的AbstractNativeSessionManager的start方法;如果我们没有指定自己的sessionDao,那么session还是存在MemorySessionDAO的ConcurrentMap<Serializable, Session> sessions中,具体可以看上述中的DefaultSessionManager。

      通过DefaultWebSessionManager实现session共享,请点此处

总结

  SecurityManager和SessionManager的类图需要认真看看;

  Subject的所有交互都会委托给SecurityManager;SecurityManager是shiro的核心,它负责与shiro的其他组件进行交互,类似SpringMVC中的DispatcherServlet或Struts2中的FilterDispatcher;

  SecurityManager会将session管理委托给SessionManager;SessionsSecurityManager的start方法中将session的创建委托给了具体的sessionManager,是创建session的关键入口。
  shiro的SimpleSession与HttpServletSession
    HttpServletSession只是servlet容器的session的装饰,最终还是依赖servlet容器,是shiro对servlet容器的session的一种支持;
    而SimpleSession是shiro完完全全的自己实现,是shiro对session的一种拓展。但SimpleSession不对外暴露,我们一般操作的是SimpleSession的代理:DelegatingSession,或者是DelegatingSession的代理:StoppingAwareProxiedSession;对session的操作,会通过一层层代理,来到DelegatingSession,DelegatingSession将session的操作转交给sessionMananger,sessionManager通过一些校验后,最后转交给SimpleSession处理。

参考

  《跟我学shiro》


  • 2017-09-05 11:48:16

    Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)

    容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器,它存放的不是文本、数值,而是对象、对象的描述(类、接口)或者是提供对象的回调,通过这种容器,我们得以实现许多高级的功能,其中最常提到的,就是 “解耦” 、“依赖注入(DI)”。本文就从这里开始。

  • 2017-09-11 09:22:09

    nginx配置返回文本或json

     有些时候请求某些接口的时候需要返回指定的文本字符串或者json字符串,如果逻辑非常简单或者干脆是固定的字符串,那么可以使用nginx快速实现,这样就不用编写程序响应请求了,可以减少服务器资源占用并且响应性能非常快

  • 2017-09-11 11:30:09

    linux 获取经过N层Nginx转发的访问来源真实IP

    通常情况下我们使用request.getRemoteAddr()就可以获取到客户端ip,但是当我们使用了nginx作为反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址。如果我们想要在web端获得用户的真实ip,就必须在nginx这里作一个赋值操作,如下:

  • 2017-09-11 16:15:11

    Nginx日志管理

    通过访问日志,你可以得到用户地域来源、跳转来源、使用终端、某个URL访问量等相关信息;通过错误日志,你可以得到系统某个服务或server的性能瓶颈等。因此,将日志好好利用,你可以得到很多有价值的信息。

  • 2017-09-11 16:34:14

    Nginx如何保留真实IP和获取前端IP

    squid,varnish以及nginx等,在做反向代理的时候,因为要代替客户端去访问服务器,所以,当请求包经过反向代理后,在代理服务器这里这个IP数据包的IP包头做了修改,最终后端web服务器得到的数据包的头部的源IP地址是代理服务器的IP地址,这样一来,后端服务器的程序给予IP的统计功能就没有任何意义,所以在做代理或集群的时候必须解决这个问题,这里,我以nginx做集群或代理的时候如何给后端web服务器保留(确切的说是传递)客户端的真实IP地址。

  • 2017-09-11 16:35:22

    ngx_http_realip_module使用详解

    网络上关于ngx_http_realip_module的文章千篇一律,全是在说怎么安装,最多贴一个示例配置,却没有说怎么用,为什么这么用,官网文档写得也十分简略,于是就自己探索了一下。

  • 2017-09-11 16:39:43

    基于Nginx dyups模块的站点动态上下线

    在分布式服务下,我们会用nginx做负载均衡, 业务站点访问某服务站点的时候, 统一走nginx, 然后nginx根据一定的轮询策略,将请求路由到后端一台指定的服务器上。