精华内容
下载资源
问答
  • Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter类似如Strut2/SpringMVC这种web框架的前端控制器,其是安全控制的入口点,其负责读取配置(如...
  • 开涛者,姓张,名开涛,齐鲁山东人氏也;任职知名互联网公司京东,因其对人和蔼,是以众人亲切称...再阅之,见作者为张开涛,随查其名百度。其下为百度简介。 张氏开涛者,撰有”开涛的博客”博客园,其所写J...

    开涛者,姓张,名开涛,齐鲁山东人氏也;任职于知名互联网公司京东,因其对人和蔼,是以众人亲切称其为”涛哥”。

     

    尚记初次见涛哥于总部某会议室,其讨论主导项目之无人便利店,当时并不知其人。于休憩之时,翻阅旁边之书籍《亿级流量网站架构核心技术》。

     

    次日晨,开涛赠吾昨日于总部所阅之书。再阅之,见作者为张开涛,随查其名于百度。其下为百度简介。

    张氏开涛者,撰有”开涛的博客”于博客园,其所写Java、SpringMVC等相关博文,访问量不下千万次;更兼著《亿级流量网站架构核心技术》一书。

     

     

     

    随对其肃然起敬,佩服其才学

     

    不久,吾亦被派遣于无人便利店之项目,负责相关之任务,有幸在其带领下学习。某次周会,亦是总部会议室初次见涛之地,已忘会议内容,但仍记开涛之语——“与他人合作之时,尽力做好所做之事,既是对已之负责,亦可增他人之信任,是以养好口碑于众人也。”

    因参与无人便利店之项目,而后与涛哥接触良多。仍记其一次与公司其他部门项目沟通,沟通良久,不得,终查为其他部门之缘由,随解决之,总耗费时日近一天。已亦心烦气燥,涛哥知前后缘由,道曰“辛苦尔,此来跨部门沟通之难也”。

    其后首次与涛哥私聊乃项目完结之时,聚于北辰新奥某海鲜餐厅。知其乃山东人氏,估其身长一米八不止,不禁在心叹曰“涛者,修长一米有八,生于齐鲁之地,不仅七尺男儿之躯,更兼才貌人品卓绝,吾不如也”。而后多次遇涛哥,其多次主动与吾问好,吾甚感惶恐亦感激之。

    “涛者何其高位也,吾新进于京东,其主动问好于吾,毫不以已位之高而斜视他人。” 随后每次见其,皆上前道好。

     

    随对其肃然起敬,佩服其人品

     

    现互联网公司跳槽何其频繁也,国外某知名互联网公司统计曰”九五后者,跳槽周期仅七月尔”。在今跳槽之风盛行,况跳槽于互联网涨薪百分之二十有亦,何乐而不为乎。 随叹曰,若遇领导、同事者皆如于开涛者,何其幸乎?

     

    转载于:https://www.cnblogs.com/zgzf/p/9917954.html

    展开全文
  • shiro cache使用

    千次阅读 2016-04-01 16:53:35
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! Shiro提供了类似于...

    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好!

    Shiro提供了类似于Spring的Cache抽象,即Shiro本身不实现Cache,但是对Cache进行了又抽象,方便更换不同的底层Cache实现。对于Cache的一些概念可以参考我的《Spring Cache抽象详解》:http://jinnianshilongnian.iteye.com/blog/2001040

     

    Shiro提供的Cache接口: 

    Java代码  收藏代码
    1. public interface Cache<K, V> {  
    2.     //根据Key获取缓存中的值  
    3.     public V get(K key) throws CacheException;  
    4.     //往缓存中放入key-value,返回缓存中之前的值  
    5.     public V put(K key, V value) throws CacheException;   
    6.     //移除缓存中key对应的值,返回该值  
    7.     public V remove(K key) throws CacheException;  
    8.     //清空整个缓存  
    9.     public void clear() throws CacheException;  
    10.     //返回缓存大小  
    11.     public int size();  
    12.     //获取缓存中所有的key  
    13.     public Set<K> keys();  
    14.     //获取缓存中所有的value  
    15.     public Collection<V> values();  
    16. }  

      

    Shiro提供的CacheManager接口: 

    Java代码  收藏代码
    1. public interface CacheManager {  
    2.     //根据缓存名字获取一个Cache  
    3.     public <K, V> Cache<K, V> getCache(String name) throws CacheException;  
    4. }  

      

    Shiro还提供了CacheManagerAware用于注入CacheManager: 

    Java代码  收藏代码
    1. public interface CacheManagerAware {  
    2.     //注入CacheManager  
    3.     void setCacheManager(CacheManager cacheManager);  
    4. }  

     

    Shiro内部相应的组件(DefaultSecurityManager)会自动检测相应的对象(如Realm)是否实现了CacheManagerAware并自动注入相应的CacheManager。

      

    本章用例使用了与第六章的代码。

     

    Realm缓存

    Shiro提供了CachingRealm,其实现了CacheManagerAware接口,提供了缓存的一些基础实现;另外AuthenticatingRealm及AuthorizingRealm分别提供了对AuthenticationInfo 和AuthorizationInfo信息的缓存。

     

    ini配置   

    Java代码  收藏代码
    1. userRealm=com.github.zhangkaitao.shiro.chapter11.realm.UserRealm  
    2. userRealm.credentialsMatcher=$credentialsMatcher  
    3. userRealm.cachingEnabled=true  
    4. userRealm.authenticationCachingEnabled=true  
    5. userRealm.authenticationCacheName=authenticationCache  
    6. userRealm.authorizationCachingEnabled=true  
    7. userRealm.authorizationCacheName=authorizationCache  
    8. securityManager.realms=$userRealm  
    9.   
    10. cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager  
    11. cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml  
    12. securityManager.cacheManager=$cacheManager   

    userRealm.cachingEnabled:启用缓存,默认false;

    userRealm.authenticationCachingEnabled:启用身份验证缓存,即缓存AuthenticationInfo信息,默认false;

    userRealm.authenticationCacheName:缓存AuthenticationInfo信息的缓存名称;

    userRealm. authorizationCachingEnabled:启用授权缓存,即缓存AuthorizationInfo信息,默认false;

    userRealm. authorizationCacheName:缓存AuthorizationInfo信息的缓存名称;

    cacheManager:缓存管理器,此处使用EhCacheManager,即Ehcache实现,需要导入相应的Ehcache依赖,请参考pom.xml;

     

    因为测试用例的关系,需要将Ehcache的CacheManager改为使用VM单例模式:

    this.manager = new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream());

    改为

    this.manager = net.sf.ehcache.CacheManager.create(getCacheManagerConfigFileInputStream());

     

    测试用例 

    Java代码  收藏代码
    1. @Test  
    2. public void testClearCachedAuthenticationInfo() {  
    3.     login(u1.getUsername(), password);  
    4.     userService.changePassword(u1.getId(), password + "1");  
    5.   
    6.     RealmSecurityManager securityManager =  
    7.      (RealmSecurityManager) SecurityUtils.getSecurityManager();  
    8.     UserRealm userRealm = (UserRealm) securityManager.getRealms().iterator().next();  
    9.     userRealm.clearCachedAuthenticationInfo(subject().getPrincipals());  
    10.   
    11.     login(u1.getUsername(), password + "1");  
    12. }   

    首先登录成功(此时会缓存相应的AuthenticationInfo),然后修改密码;此时密码就变了;接着需要调用Realm的clearCachedAuthenticationInfo方法清空之前缓存的AuthenticationInfo;否则下次登录时还会获取到修改密码之前的那个AuthenticationInfo;

     

    Java代码  收藏代码
    1. @Test  
    2. public void testClearCachedAuthorizationInfo() {  
    3.     login(u1.getUsername(), password);  
    4.     subject().checkRole(r1.getRole());  
    5.     userService.correlationRoles(u1.getId(), r2.getId());  
    6.   
    7.     RealmSecurityManager securityManager =  
    8.       (RealmSecurityManager) SecurityUtils.getSecurityManager();  
    9.     UserRealm userRealm = (UserRealm)securityManager.getRealms().iterator().next();  
    10.     userRealm.clearCachedAuthorizationInfo(subject().getPrincipals());  
    11.   
    12.     subject().checkRole(r2.getRole());  
    13. }   

    和之前的用例差不多;此处调用Realm的clearCachedAuthorizationInfo清空之前缓存的AuthorizationInfo;

     

    另外还有clearCache,其同时调用clearCachedAuthenticationInfo和clearCachedAuthorizationInfo,清空AuthenticationInfo和AuthorizationInfo。

     

    UserRealm还提供了clearAllCachedAuthorizationInfo、clearAllCachedAuthenticationInfo、clearAllCache,用于清空整个缓存。

     

    在某些清空下这种方式可能不是最好的选择,可以考虑直接废弃Shiro的缓存,然后自己通过如AOP机制实现自己的缓存;可以参考:

    https://github.com/zhangkaitao/es/tree/master/web/src/main/java/com/sishuok/es/extra/aop

     

    另外如果和Spring集成时可以考虑直接使用Spring的Cache抽象,可以考虑使用SpringCacheManagerWrapper,其对Spring Cache进行了包装,转换为Shiro的CacheManager实现:

    https://github.com/zhangkaitao/es/blob/master/web/src/main/java/org/apache/shiro/cache/spring/SpringCacheManagerWrapper.java 

     

    Session缓存

    当我们设置了SecurityManager的CacheManager时,如:

    Java代码  收藏代码
    1. securityManager.cacheManager=$cacheManager  

     

    当我们设置SessionManager时:

    Java代码  收藏代码
    1. sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager  
    2. securityManager.sessionManager=$sessionManager   

    如securityManager实现了SessionsSecurityManager,其会自动判断SessionManager是否实现了CacheManagerAware接口,如果实现了会把CacheManager设置给它。然后sessionManager会判断相应的sessionDAO(如继承自CachingSessionDAO)是否实现了CacheManagerAware,如果实现了会把CacheManager设置给它;如第九章的MySessionDAO就是带缓存的SessionDAO;其会先查缓存,如果找不到才查数据库。

     

    对于CachingSessionDAO,可以通过如下配置设置缓存的名称:

    Java代码  收藏代码
    1. sessionDAO=com.github.zhangkaitao.shiro.chapter11.session.dao.MySessionDAO  
    2. sessionDAO.activeSessionsCacheName=shiro-activeSessionCache   

    activeSessionsCacheName默认就是shiro-activeSessionCache。

    展开全文
  • shiro 的web集成使用

    2016-04-01 15:04:44
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! Shiro提供了与Web...

    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好!

    Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter类似于如Strut2/SpringMVC这种web框架的前端控制器,其是安全控制的入口点,其负责读取配置(如ini配置文件),然后判断URL是否需要登录/权限等工作。


    7.1 准备环境

    1、创建webapp应用 

    此处我们使用了jetty-maven-plugin和tomcat7-maven-plugin插件;这样可以直接使用“mvn jetty:run”或“mvn tomcat7:run”直接运行webapp了。然后通过URLhttp://localhost:8080/chapter7/访问即可。

     

    2、依赖 

    Servlet3

    Java代码  收藏代码
    1. <dependency>  
    2.     <groupId>javax.servlet</groupId>  
    3.     <artifactId>javax.servlet-api</artifactId>  
    4.     <version>3.0.1</version>  
    5.     <scope>provided</scope>  
    6. </dependency>   

    Servlet3的知识可以参考https://github.com/zhangkaitao/servlet3-showcase及Servlet3规范http://www.iteye.com/blogs/subjects/Servlet-3-1

     

    shiro-web

    Java代码  收藏代码
    1. <dependency>  
    2.     <groupId>org.apache.shiro</groupId>  
    3.     <artifactId>shiro-web</artifactId>  
    4.     <version>1.2.2</version>  
    5. </dependency>   

    其他依赖请参考源码的pom.xml。

     

    7.2 ShiroFilter入口

    1、Shiro 1.1及以前版本配置方式  

    Java代码  收藏代码
    1. <filter>  
    2.     <filter-name>iniShiroFilter</filter-name>  
    3.     <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class>  
    4.     <init-param>  
    5.         <param-name>configPath</param-name>  
    6.         <param-value>classpath:shiro.ini</param-value>  
    7.     </init-param>  
    8. </filter>  
    9. <filter-mapping>  
    10.     <filter-name>iniShiroFilter</filter-name>  
    11.     <url-pattern>/*</url-pattern>  
    12. </filter-mapping>   

    1、使用IniShiroFilter作为Shiro安全控制的入口点,通过url-pattern指定需要安全的URL;

    2、通过configPath指定ini配置文件位置,默认是先从/WEB-INF/shiro.ini加载,如果没有就默认加载classpath:shiro.ini,即默认相对于web应用上下文根路径;

    3、也可以通过如下方式直接内嵌ini配置文件内容到web.xml

    Java代码  收藏代码
    1. <init-param>  
    2.     <param-name>config</param-name>  
    3.     <param-value>  
    4.         ini配置文件贴在这  
    5.     </param-value>  
    6. </init-param>  

     

    2、Shiro 1.2及以后版本的配置方式

    从Shiro 1.2开始引入了Environment/WebEnvironment的概念,即由它们的实现提供相应的SecurityManager及其相应的依赖。ShiroFilter会自动找到Environment然后获取相应的依赖。

    Java代码  收藏代码
    1. <listener>  
    2.    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>  
    3. </listener>   

    通过EnvironmentLoaderListener来创建相应的WebEnvironment,并自动绑定到ServletContext,默认使用IniWebEnvironment实现。

     

    可以通过如下配置修改默认实现及其加载的配置文件位置:

    Java代码  收藏代码
    1. <context-param>  
    2.    <param-name>shiroEnvironmentClass</param-name>  
    3.    <param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value>  
    4. </context-param>  
    5.     <context-param>  
    6.         <param-name>shiroConfigLocations</param-name>  
    7.         <param-value>classpath:shiro.ini</param-value>  
    8.     </context-param>   

    shiroConfigLocations默认是“/WEB-INF/shiro.ini”,IniWebEnvironment默认是先从/WEB-INF/shiro.ini加载,如果没有就默认加载classpath:shiro.ini。

     

    3、与Spring集成

    Java代码  收藏代码
    1. <filter>  
    2.     <filter-name>shiroFilter</filter-name>  
    3.     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    4.     <init-param>  
    5.         <param-name>targetFilterLifecycle</param-name>  
    6.         <param-value>true</param-value>  
    7.     </init-param>  
    8. </filter>  
    9. <filter-mapping>  
    10.     <filter-name>shiroFilter</filter-name>  
    11.     <url-pattern>/*</url-pattern>  
    12. </filter-mapping>   

    DelegatingFilterProxy作用是自动到spring容器查找名字为shiroFilter(filter-name)的bean并把所有Filter的操作委托给它。然后将ShiroFilter配置到spring容器即可:

    Java代码  收藏代码
    1. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
    2. <property name="securityManager" ref="securityManager"/>  
    3. <!—忽略其他,详见与Spring集成部分 -->  
    4. </bean>   

    最后不要忘了使用org.springframework.web.context.ContextLoaderListener加载这个spring配置文件即可。

    因为我们现在的shiro版本是1.2的,因此之后的测试都是使用1.2的配置。

     

    7.3 Web INI配置

    ini配置部分和之前的相比将多出对url部分的配置。     

    Java代码  收藏代码
    1. [main]  
    2. #默认是/login.jsp  
    3. authc.loginUrl=/login  
    4. roles.unauthorizedUrl=/unauthorized  
    5. perms.unauthorizedUrl=/unauthorized  
    6. [users]  
    7. zhang=123,admin  
    8. wang=123  
    9. [roles]  
    10. admin=user:*,menu:*  
    11. [urls]  
    12. /login=anon  
    13. /unauthorized=anon  
    14. /static/**=anon  
    15. /authenticated=authc  
    16. /role=authc,roles[admin]  
    17. /permission=authc,perms["user:create"]   

    其中最重要的就是[urls]部分的配置,其格式是: “url=拦截器[参数],拦截器[参数]”;即如果当前请求的url匹配[urls]部分的某个url模式,将会执行其配置的拦截器。比如anon拦截器表示匿名访问(即不需要登录即可访问);authc拦截器表示需要身份认证通过后才能访问;roles[admin]拦截器表示需要有admin角色授权才能访问;而perms["user:create"]拦截器表示需要有“user:create”权限才能访问。

     

    url模式使用Ant风格模式

    Ant路径通配符支持?、*、**,注意通配符匹配不包括目录分隔符“/”:

    ?:匹配一个字符,如”/admin?”将匹配/admin1,但不匹配/admin或/admin2;

    *:匹配零个或多个字符串,如/admin*将匹配/admin、/admin123,但不匹配/admin/1;

    **:匹配路径中的零个或多个路径,如/admin/**将匹配/admin/a或/admin/a/b。

     

    url模式匹配顺序

    url模式匹配顺序是按照在配置中的声明顺序匹配,即从头开始使用第一个匹配的url模式对应的拦截器链。如:

    Java代码  收藏代码
    1. /bb/**=filter1  
    2. /bb/aa=filter2  
    3. /**=filter3   

    如果请求的url是“/bb/aa”,因为按照声明顺序进行匹配,那么将使用filter1进行拦截。

     

    拦截器将在下一节详细介绍。接着我们来看看身份验证、授权及退出在web中如何实现。

     

    1、身份验证(登录)

    1.1、首先配置需要身份验证的url  

    Java代码  收藏代码
    1. /authenticated=authc  
    2. /role=authc,roles[admin]  
    3. /permission=authc,perms["user:create"]   

    即访问这些地址时会首先判断用户有没有登录,如果没有登录默会跳转到登录页面,默认是/login.jsp,可以通过在[main]部分通过如下配置修改: 

    Java代码  收藏代码
    1. authc.loginUrl=/login  

     

    1.2、登录Servlet(com.github.zhangkaitao.shiro.chapter7.web.servlet.LoginServlet) 

    Java代码  收藏代码
    1. @WebServlet(name = "loginServlet", urlPatterns = "/login")  
    2. public class LoginServlet extends HttpServlet {  
    3.     @Override  
    4.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    5.       throws ServletException, IOException {  
    6.         req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, resp);  
    7.     }  
    8.     @Override  
    9.     protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
    10.       throws ServletException, IOException {  
    11.         String error = null;  
    12.         String username = req.getParameter("username");  
    13.         String password = req.getParameter("password");  
    14.         Subject subject = SecurityUtils.getSubject();  
    15.         UsernamePasswordToken token = new UsernamePasswordToken(username, password);  
    16.         try {  
    17.             subject.login(token);  
    18.         } catch (UnknownAccountException e) {  
    19.             error = "用户名/密码错误";  
    20.         } catch (IncorrectCredentialsException e) {  
    21.             error = "用户名/密码错误";  
    22.         } catch (AuthenticationException e) {  
    23.             //其他错误,比如锁定,如果想单独处理请单独catch处理  
    24.             error = "其他错误:" + e.getMessage();  
    25.         }  
    26.         if(error != null) {//出错了,返回登录页面  
    27.             req.setAttribute("error", error);  
    28.             req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, resp);  
    29.         } else {//登录成功  
    30.             req.getRequestDispatcher("/WEB-INF/jsp/loginSuccess.jsp").forward(req, resp);  
    31.         }  
    32.     }  
    33. }   

    1、doGet请求时展示登录页面;

    2、doPost时进行登录,登录时收集username/password参数,然后提交给Subject进行登录。如果有错误再返回到登录页面;否则跳转到登录成功页面(此处应该返回到访问登录页面之前的那个页面,或者没有上一个页面时访问主页)。

    3、JSP页面请参考源码。

     

    1.3、测试

    首先输入http://localhost:8080/chapter7/login进行登录,登录成功后接着可以访问http://localhost:8080/chapter7/authenticated来显示当前登录的用户: 

    Java代码  收藏代码
    1. ${subject.principal}身份验证已通过。  

    当前实现的一个缺点就是,永远返回到同一个成功页面(比如首页),在实际项目中比如支付时如果没有登录将跳转到登录页面,登录成功后再跳回到支付页面;对于这种功能大家可以在登录时把当前请求保存下来,然后登录成功后再重定向到该请求即可。

     

    Shiro内置了登录(身份验证)的实现:基于表单的和基于Basic的验证,其通过拦截器实现。

     

    2、基于Basic的拦截器身份验证

    2.1、shiro-basicfilterlogin.ini配置 

    Java代码  收藏代码
    1. [main]  
    2. authcBasic.applicationName=please login  
    3. ………省略users  
    4. [urls]  
    5. /role=authcBasic,roles[admin]   

     

    1、authcBasic是org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter类型的实例,其用于实现基于Basic的身份验证;applicationName用于弹出的登录框显示信息使用,如图:



    2、[urls]部分配置了/role地址需要走authcBasic拦截器,即如果访问/role时还没有通过身份验证那么将弹出如上图的对话框进行登录,登录成功即可访问。

     

    2.2、web.xml

    把shiroConfigLocations改为shiro-basicfilterlogin.ini即可。

     

    2.3、测试

    输入http://localhost:8080/chapter7/role,会弹出之前的Basic验证对话框输入“zhang/123”即可登录成功进行访问。

     

    3、基于表单的拦截器身份验证

    基于表单的拦截器身份验证和【1】类似,但是更简单,因为其已经实现了大部分登录逻辑;我们只需要指定:登录地址/登录失败后错误信息存哪/成功的地址即可。

      

    3.1、shiro-formfilterlogin.ini 

    Java代码  收藏代码
    1. [main]  
    2. authc.loginUrl=/formfilterlogin  
    3. authc.usernameParam=username  
    4. authc.passwordParam=password  
    5. authc.successUrl=/  
    6. authc.failureKeyAttribute=shiroLoginFailure  
    7.   
    8. [urls]  
    9. /role=authc,roles[admin]   

    1、authc是org.apache.shiro.web.filter.authc.FormAuthenticationFilter类型的实例,其用于实现基于表单的身份验证;通过loginUrl指定当身份验证时的登录表单;usernameParam指定登录表单提交的用户名参数名;passwordParam指定登录表单提交的密码参数名;successUrl指定登录成功后重定向的默认地址(默认是“/”)(如果有上一个地址会自动重定向带该地址);failureKeyAttribute指定登录失败时的request属性key(默认shiroLoginFailure);这样可以在登录表单得到该错误key显示相应的错误消息;

     

    3.2、web.xml

    把shiroConfigLocations改为shiro- formfilterlogin.ini即可。

     

    3.3、登录Servlet 

    Java代码  收藏代码
    1. @WebServlet(name = "formFilterLoginServlet", urlPatterns = "/formfilterlogin")  
    2. public class FormFilterLoginServlet extends HttpServlet {  
    3.     @Override  
    4.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    5.       throws ServletException, IOException {  
    6.         doPost(req, resp);  
    7.     }  
    8.     @Override  
    9.     protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
    10.      throws ServletException, IOException {  
    11.         String errorClassName = (String)req.getAttribute("shiroLoginFailure");  
    12.         if(UnknownAccountException.class.getName().equals(errorClassName)) {  
    13.             req.setAttribute("error""用户名/密码错误");  
    14.         } else if(IncorrectCredentialsException.class.getName().equals(errorClassName)) {  
    15.             req.setAttribute("error""用户名/密码错误");  
    16.         } else if(errorClassName != null) {  
    17.             req.setAttribute("error""未知错误:" + errorClassName);  
    18.         }  
    19.         req.getRequestDispatcher("/WEB-INF/jsp/formfilterlogin.jsp").forward(req, resp);  
    20.     }  
    21. }  

    在登录Servlet中通过shiroLoginFailure得到authc登录失败时的异常类型名,然后根据此异常名来决定显示什么错误消息。

     

    4、测试

    输入http://localhost:8080/chapter7/role,会跳转到“/formfilterlogin”登录表单,提交表单如果authc拦截器登录成功后,会直接重定向会之前的地址“/role”;假设我们直接访问“/formfilterlogin”的话登录成功将直接到默认的successUrl。

     

    4、授权(角色/权限验证)

    4.1、shiro.ini   

    Java代码  收藏代码
    1. [main]  
    2. roles.unauthorizedUrl=/unauthorized  
    3. perms.unauthorizedUrl=/unauthorized  
    4.  [urls]  
    5. /role=authc,roles[admin]  
    6. /permission=authc,perms["user:create"]   

    通过unauthorizedUrl属性指定如果授权失败时重定向到的地址。roles是org.apache.shiro.web.filter.authz.RolesAuthorizationFilter类型的实例,通过参数指定访问时需要的角色,如“[admin]”,如果有多个使用“,”分割,且验证时是hasAllRole验证,即且的关系。Perms是org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter类型的实例,和roles类似,只是验证权限字符串。

     

    4.2、web.xml

    把shiroConfigLocations改为shiro.ini即可。

     

    4.3、RoleServlet/PermissionServlet  

    Java代码  收藏代码
    1. @WebServlet(name = "permissionServlet", urlPatterns = "/permission")  
    2. public class PermissionServlet extends HttpServlet {  
    3.     @Override  
    4.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    5.       throws ServletException, IOException {  
    6.         Subject subject = SecurityUtils.getSubject();  
    7.         subject.checkPermission("user:create");  
    8.         req.getRequestDispatcher("/WEB-INF/jsp/hasPermission.jsp").forward(req, resp);  
    9.     }  
    10. }  
    Java代码  收藏代码
    1. @WebServlet(name = "roleServlet", urlPatterns = "/role")  
    2. public class RoleServlet extends HttpServlet {  
    3.     @Override  
    4.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    5.       throws ServletException, IOException {  
    6.         Subject subject = SecurityUtils.getSubject();  
    7.         subject.checkRole("admin");  
    8.         req.getRequestDispatcher("/WEB-INF/jsp/hasRole.jsp").forward(req, resp);  
    9.     }  
    10. }   

     

    4.4、测试

    首先访问http://localhost:8080/chapter7/login,使用帐号“zhang/123”进行登录,再访问/role或/permission时会跳转到成功页面(因为其授权成功了);如果使用帐号“wang/123”登录成功后访问这两个地址会跳转到“/unauthorized”即没有授权页面。

     

    5、退出

    5.1、shiro.ini 

    Java代码  收藏代码
    1. [urls]  
    2. /logout=anon   

    指定/logout使用anon拦截器即可,即不需要登录即可访问。

     

    5.2、LogoutServlet

    Java代码  收藏代码
    1. @WebServlet(name = "logoutServlet", urlPatterns = "/logout")  
    2. public class LogoutServlet extends HttpServlet {  
    3.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    4.       throws ServletException, IOException {  
    5.         SecurityUtils.getSubject().logout();  
    6.         req.getRequestDispatcher("/WEB-INF/jsp/logoutSuccess.jsp").forward(req, resp);  
    7.     }  
    8. }   

    直接调用Subject.logout即可,退出成功后转发/重定向到相应页面即可。

     

    5.3、测试

    首先访问http://localhost:8080/chapter7/login,使用帐号“zhang/123”进行登录,登录成功后访问/logout即可退出。

     

    Shiro也提供了logout拦截器用于退出,其是org.apache.shiro.web.filter.authc.LogoutFilter类型的实例,我们可以在shiro.ini配置文件中通过如下配置完成退出:

    Java代码  收藏代码
    1. [main]  
    2. logout.redirectUrl=/login  
    3.   
    4. [urls]  
    5. /logout2=logout   

    通过logout.redirectUrl指定退出后重定向的地址;通过/logout2=logout指定退出url是/logout2。这样当我们登录成功后然后访问/logout2即可退出。

    展开全文
  • shiro 会话管理

    千次阅读 2016-04-01 16:11:28
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! Shiro提供了完整的...

    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好!


    Shiro提供了完整的企业级会话管理功能,不依赖于底层容器(如web容器tomcat),不管JavaSE还是JavaEE环境都可以使用,提供了会话管理、会话事件监听、会话存储/持久化、容器无关的集群、失效/过期支持、对Web的透明支持、SSO单点登录的支持等特性。即直接使用Shiro的会话管理可以直接替换如Web容器的会话管理。

     

    会话

    所谓会话,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。如访问一些网站时登录成功后,网站可以记住用户,且在退出之前都可以识别当前用户是谁。

     

     

    Shiro的会话支持不仅可以在普通的JavaSE应用中使用,也可以在JavaEE应用中使用,如web应用。且使用方式是一致的。 

    Java代码  收藏代码
    1. login("classpath:shiro.ini""zhang""123");  
    2. Subject subject = SecurityUtils.getSubject();  
    3. Session session = subject.getSession();   

    登录成功后使用Subject.getSession()即可获取会话;其等价于Subject.getSession(true),即如果当前没有创建Session对象会创建一个;另外Subject.getSession(false),如果当前没有创建Session则返回null(不过默认情况下如果启用会话存储功能的话在创建Subject时会主动创建一个Session)。

     

    Java代码  收藏代码
    1. session.getId();  

    获取当前会话的唯一标识。

      

    Java代码  收藏代码
    1. session.getHost();  

    获取当前Subject的主机地址,该地址是通过HostAuthenticationToken.getHost()提供的。 

     

    Java代码  收藏代码
    1. session.getTimeout();  
    2. session.setTimeout(毫秒);   

    获取/设置当前Session的过期时间;如果不设置默认是会话管理器的全局过期时间。

      

    Java代码  收藏代码
    1. session.getStartTimestamp();  
    2. session.getLastAccessTime();  

    获取会话的启动时间及最后访问时间;如果是JavaSE应用需要自己定期调用session.touch()去更新最后访问时间;如果是Web应用,每次进入ShiroFilter都会自动调用session.touch()来更新最后访问时间。    

     

    Java代码  收藏代码
    1. session.touch();  
    2. session.stop();   

    更新会话最后访问时间及销毁会话;当Subject.logout()时会自动调用stop方法来销毁会话。如果在web中,调用javax.servlet.http.HttpSession. invalidate()也会自动调用Shiro Session.stop方法进行销毁Shiro的会话。 

     

    Java代码  收藏代码
    1. session.setAttribute("key""123");  
    2. Assert.assertEquals("123", session.getAttribute("key"));  
    3. session.removeAttribute("key");  

    设置/获取/删除会话属性;在整个会话范围内都可以对这些属性进行操作。 

     

    Shiro提供的会话可以用于JavaSE/JavaEE环境,不依赖于任何底层容器,可以独立使用,是完整的会话模块。

     

    会话管理器

    会话管理器管理着应用中所有Subject的会话的创建、维护、删除、失效、验证等工作。是Shiro的核心组件,顶层组件SecurityManager直接继承了SessionManager,且提供了SessionsSecurityManager实现直接把会话管理委托给相应的SessionManager,DefaultSecurityManager及DefaultWebSecurityManager默认SecurityManager都继承了SessionsSecurityManager。

     

     

    SecurityManager提供了如下接口:

     

    Java代码  收藏代码
    1. Session start(SessionContext context); //启动会话  
    2. Session getSession(SessionKey key) throws SessionException; //根据会话Key获取会话   

     

    另外用于Web环境的WebSessionManager又提供了如下接口:

     

    Java代码  收藏代码
    1. boolean isServletContainerSessions();//是否使用Servlet容器的会话  

     

    Shiro还提供了ValidatingSessionManager用于验资并过期会话: 

    Java代码  收藏代码
    1. void validateSessions();//验证所有会话是否过期  


     

    Shiro提供了三个默认实现:

    DefaultSessionManager:DefaultSecurityManager使用的默认实现,用于JavaSE环境;

    ServletContainerSessionManager:DefaultWebSecurityManager使用的默认实现,用于Web环境,其直接使用Servlet容器的会话;

    DefaultWebSessionManager:用于Web环境的实现,可以替代ServletContainerSessionManager,自己维护着会话,直接废弃了Servlet容器的会话管理。

     

    替换SecurityManager默认的SessionManager可以在ini中配置(shiro.ini):

     

    Java代码  收藏代码
    1. [main]  
    2. sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager  
    3. securityManager.sessionManager=$sessionManager   

     

     

    Web环境下的ini配置(shiro-web.ini):

     

    <!--EndFragment-->

     

    Java代码  收藏代码
    1. [main]  
    2. sessionManager=org.apache.shiro.web.session.mgt.ServletContainerSessionManager  
    3. securityManager.sessionManager=$sessionManager  

       

     

    另外可以设置会话的全局过期时间(毫秒为单位),默认30分钟:

     

    Java代码  收藏代码
    1. sessionManager. globalSessionTimeout=1800000   

     

    默认情况下globalSessionTimeout将应用给所有Session。可以单独设置每个Session的timeout属性来为每个Session设置其超时时间。

     

    另外如果使用ServletContainerSessionManager进行会话管理,Session的超时依赖于底层Servlet容器的超时时间,可以在web.xml中配置其会话的超时时间(分钟为单位): 

    Java代码  收藏代码
    1. <session-config>  
    2.   <session-timeout>30</session-timeout>  
    3. </session-config>  

      

    在Servlet容器中,默认使用JSESSIONID Cookie维护会话,且会话默认是跟容器绑定的;在某些情况下可能需要使用自己的会话机制,此时我们可以使用DefaultWebSessionManager来维护会话:

    Java代码  收藏代码
    1. sessionIdCookie=org.apache.shiro.web.servlet.SimpleCookie  
    2. sessionManager=org.apache.shiro.web.session.mgt.DefaultWebSessionManager  
    3. sessionIdCookie.name=sid  
    4. #sessionIdCookie.domain=sishuok.com  
    5. #sessionIdCookie.path=  
    6. sessionIdCookie.maxAge=1800  
    7. sessionIdCookie.httpOnly=true  
    8. sessionManager.sessionIdCookie=$sessionIdCookie  
    9. sessionManager.sessionIdCookieEnabled=true  
    10. securityManager.sessionManager=$sessionManager   

    sessionIdCookie是sessionManager创建会话Cookie的模板:

    sessionIdCookie.name:设置Cookie名字,默认为JSESSIONID;

    sessionIdCookie.domain:设置Cookie的域名,默认空,即当前访问的域名;

    sessionIdCookie.path:设置Cookie的路径,默认空,即存储在域名根下;

    sessionIdCookie.maxAge:设置Cookie的过期时间,秒为单位,默认-1表示关闭浏览器时过期Cookie;

    sessionIdCookie.httpOnly:如果设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击;此特性需要实现了Servlet 2.5 MR6及以上版本的规范的Servlet容器支持;

    sessionManager.sessionIdCookieEnabled:是否启用/禁用Session Id Cookie,默认是启用的;如果禁用后将不会设置Session Id Cookie,即默认使用了Servlet容器的JSESSIONID,且通过URL重写(URL中的“;JSESSIONID=id”部分)保存Session Id。

     

    另外我们可以如“sessionManager. sessionIdCookie.name=sid”这种方式操作Cookie模板。

     

    会话监听器

    会话监听器用于监听会话创建、过期及停止事件: 

    Java代码  收藏代码
    1. public class MySessionListener1 implements SessionListener {  
    2.     @Override  
    3.     public void onStart(Session session) {//会话创建时触发  
    4.         System.out.println("会话创建:" + session.getId());  
    5.     }  
    6.     @Override  
    7.     public void onExpiration(Session session) {//会话过期时触发  
    8.         System.out.println("会话过期:" + session.getId());  
    9.     }  
    10.     @Override  
    11.     public void onStop(Session session) {//退出/会话过期时触发  
    12.         System.out.println("会话停止:" + session.getId());  
    13.     }    
    14. }  

     

    如果只想监听某一个事件,可以继承SessionListenerAdapter实现:

    Java代码  收藏代码
    1. public class MySessionListener2 extends SessionListenerAdapter {  
    2.     @Override  
    3.     public void onStart(Session session) {  
    4.         System.out.println("会话创建:" + session.getId());  
    5.     }  
    6. }  

     

    在shiro-web.ini配置文件中可以进行如下配置设置会话监听器:

    Java代码  收藏代码
    1. sessionListener1=com.github.zhangkaitao.shiro.chapter10.web.listener.MySessionListener1  
    2. sessionListener2=com.github.zhangkaitao.shiro.chapter10.web.listener.MySessionListener2  
    3. sessionManager.sessionListeners=$sessionListener1,$sessionListener2  

     

    会话存储/持久化 

    Shiro提供SessionDAO用于会话的CRUD,即DAO(Data Access Object)模式实现:

    Java代码  收藏代码
    1. //如DefaultSessionManager在创建完session后会调用该方法;如保存到关系数据库/文件系统/NoSQL数据库;即可以实现会话的持久化;返回会话ID;主要此处返回的ID.equals(session.getId());  
    2. Serializable create(Session session);  
    3. //根据会话ID获取会话  
    4. Session readSession(Serializable sessionId) throws UnknownSessionException;  
    5. //更新会话;如更新会话最后访问时间/停止会话/设置超时时间/设置移除属性等会调用  
    6. void update(Session session) throws UnknownSessionException;  
    7. //删除会话;当会话过期/会话停止(如用户退出时)会调用  
    8. void delete(Session session);  
    9. //获取当前所有活跃用户,如果用户量多此方法影响性能  
    10. Collection<Session> getActiveSessions();   

    Shiro内嵌了如下SessionDAO实现:

    AbstractSessionDAO提供了SessionDAO的基础实现,如生成会话ID等;CachingSessionDAO提供了对开发者透明的会话缓存的功能,只需要设置相应的CacheManager即可;MemorySessionDAO直接在内存中进行会话维护;而EnterpriseCacheSessionDAO提供了缓存功能的会话维护,默认情况下使用MapCache实现,内部使用ConcurrentHashMap保存缓存的会话。

     

    可以通过如下配置设置SessionDAO:

    Java代码  收藏代码
    1. sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO  
    2. sessionManager.sessionDAO=$sessionDAO   

    Shiro提供了使用Ehcache进行会话存储,Ehcache可以配合TerraCotta实现容器无关的分布式集群。

     

    首先在pom.xml里添加如下依赖:

    Java代码  收藏代码
    1. <dependency>  
    2.     <groupId>org.apache.shiro</groupId>  
    3.     <artifactId>shiro-ehcache</artifactId>  
    4.     <version>1.2.2</version>  
    5. </dependency>   

     

    接着配置shiro-web.ini文件:    

    Java代码  收藏代码
    1. sessionDAO=org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO  
    2. sessionDAO. activeSessionsCacheName=shiro-activeSessionCache  
    3. sessionManager.sessionDAO=$sessionDAO  
    4. cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager  
    5. cacheManager.cacheManagerConfigFile=classpath:ehcache.xml  
    6. securityManager.cacheManager = $cacheManager   

    sessionDAO. activeSessionsCacheName:设置Session缓存名字,默认就是shiro-activeSessionCache;

    cacheManager:缓存管理器,用于管理缓存的,此处使用Ehcache实现;

    cacheManager.cacheManagerConfigFile:设置ehcache缓存的配置文件;

    securityManager.cacheManager:设置SecurityManager的cacheManager,会自动设置实现了CacheManagerAware接口的相应对象,如SessionDAO的cacheManager;

     

    然后配置ehcache.xml:

    Java代码  收藏代码
    1. <cache name="shiro-activeSessionCache"  
    2.        maxEntriesLocalHeap="10000"  
    3.        overflowToDisk="false"  
    4.        eternal="false"  
    5.        diskPersistent="false"  
    6.        timeToLiveSeconds="0"  
    7.        timeToIdleSeconds="0"  
    8.        statistics="true"/>   

    Cache的名字为shiro-activeSessionCache,即设置的sessionDAO的activeSessionsCacheName属性值。

     

    另外可以通过如下ini配置设置会话ID生成器:

    Java代码  收藏代码
    1. sessionIdGenerator=org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator  
    2. sessionDAO.sessionIdGenerator=$sessionIdGenerator   

    用于生成会话ID,默认就是JavaUuidSessionIdGenerator,使用java.util.UUID生成。

     

    如果自定义实现SessionDAO,继承CachingSessionDAO即可:

    Java代码  收藏代码
    1. public class MySessionDAO extends CachingSessionDAO {  
    2.     private JdbcTemplate jdbcTemplate = JdbcTemplateUtils.jdbcTemplate();  
    3.      protected Serializable doCreate(Session session) {  
    4.         Serializable sessionId = generateSessionId(session);  
    5.         assignSessionId(session, sessionId);  
    6.         String sql = "insert into sessions(id, session) values(?,?)";  
    7.         jdbcTemplate.update(sql, sessionId, SerializableUtils.serialize(session));  
    8.         return session.getId();  
    9.     }  
    10. protected void doUpdate(Session session) {  
    11.     if(session instanceof ValidatingSession && !((ValidatingSession)session).isValid()) {  
    12.         return//如果会话过期/停止 没必要再更新了  
    13.     }  
    14.         String sql = "update sessions set session=? where id=?";  
    15.         jdbcTemplate.update(sql, SerializableUtils.serialize(session), session.getId());  
    16.     }  
    17.     protected void doDelete(Session session) {  
    18.         String sql = "delete from sessions where id=?";  
    19.         jdbcTemplate.update(sql, session.getId());  
    20.     }  
    21.     protected Session doReadSession(Serializable sessionId) {  
    22.         String sql = "select session from sessions where id=?";  
    23.         List<String> sessionStrList = jdbcTemplate.queryForList(sql, String.class, sessionId);  
    24.         if(sessionStrList.size() == 0return null;  
    25.         return SerializableUtils.deserialize(sessionStrList.get(0));  
    26.     }  
    27. }   

    doCreate/doUpdate/doDelete/doReadSession分别代表创建/修改/删除/读取会话;此处通过把会话序列化后存储到数据库实现;接着在shiro-web.ini中配置:

    Java代码  收藏代码
    1. sessionDAO=com.github.zhangkaitao.shiro.chapter10.session.dao.MySessionDAO  

    其他设置和之前一样,因为继承了CachingSessionDAO;所有在读取时会先查缓存中是否存在,如果找不到才到数据库中查找。

     

    会话验证

    Shiro提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话;出于性能考虑,一般情况下都是获取会话时来验证会话是否过期并停止会话的;但是如在web环境中,如果用户不主动退出是不知道会话是否过期的,因此需要定期的检测会话是否过期,Shiro提供了会话验证调度器SessionValidationScheduler来做这件事情。

     

    可以通过如下ini配置开启会话验证:    

    Java代码  收藏代码
    1. sessionValidationScheduler=org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler  
    2. sessionValidationScheduler.interval = 3600000  
    3. sessionValidationScheduler.sessionManager=$sessionManager  
    4. sessionManager.globalSessionTimeout=1800000  
    5. sessionManager.sessionValidationSchedulerEnabled=true  
    6. sessionManager.sessionValidationScheduler=$sessionValidationScheduler   

    sessionValidationScheduler:会话验证调度器,sessionManager默认就是使用ExecutorServiceSessionValidationScheduler,其使用JDK的ScheduledExecutorService进行定期调度并验证会话是否过期;

    sessionValidationScheduler.interval:设置调度时间间隔,单位毫秒,默认就是1小时;

    sessionValidationScheduler.sessionManager:设置会话验证调度器进行会话验证时的会话管理器;

    sessionManager.globalSessionTimeout:设置全局会话超时时间,默认30分钟,即如果30分钟内没有访问会话将过期;

    sessionManager.sessionValidationSchedulerEnabled:是否开启会话验证器,默认是开启的;

    sessionManager.sessionValidationScheduler:设置会话验证调度器,默认就是使用ExecutorServiceSessionValidationScheduler。

     

    Shiro也提供了使用Quartz会话验证调度器:

    Java代码  收藏代码
    1. sessionValidationScheduler=org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler  
    2. sessionValidationScheduler.sessionValidationInterval = 3600000  
    3. sessionValidationScheduler.sessionManager=$sessionManager   

    使用时需要导入shiro-quartz依赖:

    Java代码  收藏代码
    1. <dependency>  
    2.      <groupId>org.apache.shiro</groupId>  
    3.      <artifactId>shiro-quartz</artifactId>  
    4.      <version>1.2.2</version>  
    5. </dependency>  

        

    如上会话验证调度器实现都是直接调用AbstractValidatingSessionManager 的validateSessions方法进行验证,其直接调用SessionDAO的getActiveSessions方法获取所有会话进行验证,如果会话比较多,会影响性能;可以考虑如分页获取会话并进行验证,如com.github.zhangkaitao.shiro.chapter10.session.scheduler.MySessionValidationScheduler:

    Java代码  收藏代码
    1. //分页获取会话并验证  
    2. String sql = "select session from sessions limit ?,?";  
    3. int start = 0//起始记录  
    4. int size = 20//每页大小  
    5. List<String> sessionList = jdbcTemplate.queryForList(sql, String.class, start, size);  
    6. while(sessionList.size() > 0) {  
    7.   for(String sessionStr : sessionList) {  
    8.     try {  
    9.       Session session = SerializableUtils.deserialize(sessionStr);  
    10.       Method validateMethod =   
    11.         ReflectionUtils.findMethod(AbstractValidatingSessionManager.class,   
    12.             "validate", Session.class, SessionKey.class);  
    13.       validateMethod.setAccessible(true);  
    14.       ReflectionUtils.invokeMethod(validateMethod,   
    15.         sessionManager, session, new DefaultSessionKey(session.getId()));  
    16.     } catch (Exception e) {  
    17.         //ignore  
    18.     }  
    19.   }  
    20.  start = start + size;  
    21.   sessionList = jdbcTemplate.queryForList(sql, String.class, start, size);  
    22. }   

    其直接改造自ExecutorServiceSessionValidationScheduler,如上代码是验证的核心代码,可以根据自己的需求改造此验证调度器器;ini的配置和之前的类似。

     

    如果在会话过期时不想删除过期的会话,可以通过如下ini配置进行设置:

    Java代码  收藏代码
    1. sessionManager.deleteInvalidSessions=false  

    默认是开启的,在会话过期后会调用SessionDAO的delete方法删除会话:如会话时持久化存储的,可以调用此方法进行删除。

     

    如果是在获取会话时验证了会话已过期,将抛出InvalidSessionException;因此需要捕获这个异常并跳转到相应的页面告诉用户会话已过期,让其重新登录,如可以在web.xml配置相应的错误页面:

    Java代码  收藏代码
    1. <error-page>  
    2.     <exception-type>org.apache.shiro.session.InvalidSessionException</exception-type>  
    3.     <location>/invalidSession.jsp</location>  
    4. </error-page>  

     

    sessionFactory

    sessionFactory是创建会话的工厂,根据相应的Subject上下文信息来创建会话;默认提供了SimpleSessionFactory用来创建SimpleSession会话。

     

    首先自定义一个Session:

    Java代码  收藏代码
    1. public class OnlineSession extends SimpleSession {  
    2.     public static enum OnlineStatus {  
    3.         on_line("在线"), hidden("隐身"), force_logout("强制退出");  
    4.         private final String info;  
    5.         private OnlineStatus(String info) {  
    6.             this.info = info;  
    7.         }  
    8.         public String getInfo() {  
    9.             return info;  
    10.         }  
    11.     }  
    12.     private String userAgent; //用户浏览器类型  
    13.     private OnlineStatus status = OnlineStatus.on_line; //在线状态  
    14.     private String systemHost; //用户登录时系统IP  
    15.     //省略其他  
    16. }   

    OnlineSession用于保存当前登录用户的在线状态,支持如离线等状态的控制。

     

    接着自定义SessionFactory:

    Java代码  收藏代码
    1. public class OnlineSessionFactory implements SessionFactory {  
    2.   
    3.     @Override  
    4.     public Session createSession(SessionContext initData) {  
    5.         OnlineSession session = new OnlineSession();  
    6.         if (initData != null && initData instanceof WebSessionContext) {  
    7.             WebSessionContext sessionContext = (WebSessionContext) initData;  
    8.             HttpServletRequest request = (HttpServletRequest) sessionContext.getServletRequest();  
    9.             if (request != null) {  
    10.                 session.setHost(IpUtils.getIpAddr(request));  
    11.                 session.setUserAgent(request.getHeader("User-Agent"));  
    12.                 session.setSystemHost(request.getLocalAddr() + ":" + request.getLocalPort());  
    13.             }  
    14.         }  
    15.         return session;  
    16.     }  
    17. }   

    根据会话上下文创建相应的OnlineSession。

     

    最后在shiro-web.ini配置文件中配置:

    Java代码  收藏代码
    1. sessionFactory=org.apache.shiro.session.mgt.OnlineSessionFactory  
    2. sessionManager.sessionFactory=$sessionFactory  
    展开全文
  • shiro Realm及相关对象

    2016-04-01 14:37:36
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! 6.1 Realm 【2.5 ...
  • shiro 与spring集成

    2016-04-01 17:35:32
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! Shiro的组件都是...
  • zhangkaitao(张开涛) 参赛感言: 写博客是一种分享态度。 开博一年多,主要写java框架spring相关内容,一年多让我收获很多,也让我喜欢上了写博客。好记性不如烂笔头,把工作中、学习中遇到的记录下来,方便...
  • shiro 编码解码

    2016-04-01 13:37:44
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! 在涉及到密码...
  • shiro身份认证

    2016-04-01 10:05:03
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2019547,谢谢开涛的无私分享,我觉得讲的很好! 身份验证,即在应用中...
  • shiro 授权

    2016-04-01 13:11:27
    此文章是分享于开涛写的shiro,本人只是用来作为学习笔记,如果觉得我不尊重原创者,请点击此处:http://jinnianshilongnian.iteye.com/blog/2018936,谢谢开涛的无私分享,我觉得讲的很好! 授权,也叫访问...
  • 授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。...
  • 相当SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。 ...
  • 相当Subject.getPrincipals().oneByType(String.class)。    Java代码   type= "java.lang.String" />  相当Subject.getPrincipals().oneByType(String.class)。   ...
  • ini配置文件类似Java中的properties(key=value),不过提供了将key/value分类的特性,key是每个部分不重复即可,而不是整个配置文件。如下是INI配置分类:  Java代码  [main]  #提供了对根...
  • 一个项目两部电脑 ...张开涛亲笔签名 ...* 文中部分内容来源网络。 Java我最强 关心Java人成长的技术内容社区 快速关注
  • Shiro提供了类似Spring的Cache抽象,即Shiro本身不实现Cache,但是对Cache进行了又抽象,方便更换不同的底层Cache实现。对于Cache的一些概念可以参考我的《Spring Cache抽象详解》:...
  • Shiro提供了与Web集成的支持,其通过一个ShiroFilter入口来拦截需要安全控制的URL,然后进行相应的控制,ShiroFilter类似如Strut2/SpringMVC这种web框架的前端控制器,其是安全控制的入口点,其负责读取配置(如...
  • AdviceFilter提供了AOP风格的支持,类似SpringMVC中的Interceptor: Java代码  boolean  preHandle(ServletRequest request, ServletResponse response)  throws  Exception  void  ...
  • Account相当我们之前的User,SimpleAccount是其一个实现;在IniRealm、PropertiesRealm这种静态创建帐号信息的场景中使用,这些Realm直接继承了SimpleAccountRealm,而SimpleAccountRealm提供了相关的API来动态...
  • 前边IoC一章我们已经了解了Bean依赖容器,那容器 如何注入Bean的依赖资源, Spring IoC 容器注入依赖资源 主要有以下两种基本实现方式: ...:就是容器实例化Bean时注入那些依赖,通过在在Bean...,其等价。  
  • 在Spring容器中存储如图3-5所示,Spring不仅会缓存单例对象,Bean定义也是会缓存的,对于惰性初始化的对象是在首次使用时根据Bean定义创建并存放单例缓存池。  惰性初始化 的目的是延迟对象的初始化,直到...
  • Spring Boot JWT oauth

    2018-03-26 10:21:46
    oauth原理简述oauth本身不是...想深入研究原理的 可以参考:阮一峰的博客以及张开涛的博客借用开涛老师一张图,就是整个oauth2.0 的协议实现原理,所有的技术层面的开发都是围绕这张图。整个开发流程简述一下:1、 ...
  • 上半年看了一些书,简单总结一下 坚持阅读 古人云:“活到老,学到老。” IT技术发展太快,行业...1.《亿级流量-高并发高可用架构实战》张开涛 江湖人称”涛哥”,京东大牛,一次偶然的机会,通过中生代...
  • 原创:张开涛开涛的博客2017-03-24 本篇摘自《亿级流量网站架构核心技术》第二章 Nginx负载均衡与反向代理 部分内容。 当我们的应用单实例不能支撑用户请求时,此时就需要扩容,从一台服务器扩容到两台、几十台、...
  • 10分钟学会如何使用Shiro

    千次阅读 2017-07-11 15:52:33
    本篇内容大多总结自张开涛的《跟我学Shiro》原文地址:http://jinnianshilongnian.iteye.com/blog/2018936我并没有全部看完,只是选择了一部分对我来说急需在项目中使用的知识加以学习。并且对于大多数第一次接触...
  • 原文出处:张开涛 9.1 数据库事务概述 事务首先是一系列操作组成的工作单元,该工作单元内的操作是不可分割的,即要么所有操作都做,要么所有操作都不做,这就是事务。 事务必需满足ACID(原子性、一致性、隔离性...
  • 一个码砖的码农,在CSDN写一年博客,出书了?

    千次阅读 多人点赞 2021-04-23 09:39:14
    在20年10月1日放假起,我开始重新整理设计模式稿件,重新整理文章、收集粉丝反馈、绘制技术图稿,一点点的完成所有内容并添加新的章节,11月左右交给出版社,接下来的路漫漫长… 一本书的出版要选题、交稿、审稿、...
  •  1、亿级流量网站架构核心技术+跟开涛学搭建高可用高并发系统---张开涛  相比之前读的李智慧的《大型网络技术架构》更加的细致,让自己的知识体系更加的丰富;比如:自己之前也搞过nginx当时自己还有一个疑问...
  • 当时他们找不到适用应用程序级别的合适 Java 安全框架,同时又对 JAAS 非常失望,于是就搞了这个东西。 2004 年到 2008 年期间,JSecurity 托管在 SourceForge 上,贡献者包括 Peter Ledbrook、Alan Ditzel 和 Tim...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 529
精华内容 211
关键字:

于开涛