Shiro - 会话超时后重定向到登录页面

时间:2018-05-14 18:45:27

标签: java session web.xml shiro

当会话超时时,我需要将我的webapp(Java + angular)重定向到登录页面。 shiro是自动进行重定向还是由代码处理?

我尝试了几次黑客攻击,但对我来说并不起作用。 我尝试将会话超时添加到我的web.xml,但它根本没有生效。 我尝试更新我的shiro.ini,但随后又无法登录我的应用程序了!

您能否帮助找出这些文件中的错误或建议在这种情况下应该做些什么。

提前致谢。

的web.xml:



<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>ResourceManager</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <!-- session-config>
    <session-timeout>1</session-timeout>
  </session-config>

  <error-page>
    <exception-type>javax.faces.application.ViewExpiredException</exception-type>
    <location>/Login.html</location>
  </error-page-->
  
  <listener>
    <listener-class>
    	com.<our customized package>.logging.AppLifeCircleListener
    	</listener-class>
  </listener>
  <listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
  </listener>
  <filter>
    <filter-name>shiro-filter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>shiro-filter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>
  <servlet>
    <servlet-name>login</servlet-name>
    <jsp-file>/Login.jsp</jsp-file>
  </servlet>
  <servlet>
    <servlet-name>rest</servlet-name>
    <servlet-class>
  			org.springframework.web.servlet.DispatcherServlet
 		</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/rest-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/management/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/privilege/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>rest</servlet-name>
    <url-pattern>/file-explorer/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>login</servlet-name>
    <url-pattern>/Login.html</url-pattern>
  </servlet-mapping>
</web-app>
&#13;
&#13;
&#13;

shiro.ini:

&#13;
&#13;
[main]

# LDAP Settinng
contextFactory = com.ibm.datafabrication.web.server.security.JndiLdapContextFactoryExt
contextFactory.url = ldap://<host>:389
contextFactory.systemUsername = <...>
contextFactory.keyPath = <>
contextFactory.encodedSystemPassword = ...

ldapRealm = com.<>.ActiveDirectoryRealm
ldapRealm.ldapContextFactory = $contextFactory
ldapRealm.userSearchFilter = (sAMAccountName={0})
ldapRealm.groupNameAttribute = cn
ldapRealm.searchBase = DC=<...>,DC=<...>,DC=com
ldapRealm.groupRolesMap = dfp_users:user,dfp_admins:admin

# SQLite Setting
ds = org.sqlite.SQLiteDataSource
ds.url = jdbc:sqlite:<>.db
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource = $ds
jdbcRealm.permissionsLookupEnabled = false
jdbcRealm.authenticationQuery = SELECT Password FROM Users WHERE Name=?
jdbcRealm.userRolesQuery = WITH uname(name) AS (VALUES(?)) SELECT 'user' FROM Users, uname WHERE Users.Name=uname.name UNION ALL SELECT 'admin' FROM (SELECT Id FROM Users, uname WHERE Users.Name=uname.name) LEFT JOIN Admins on Id = Admins.UserId WHERE UserId NOT NULL
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
credentialsMatcher.storedCredentialsHexEncoded = true
jdbcRealm.credentialsMatcher = $credentialsMatcher

authc.loginUrl = /Login.html
securityManager.realms = $jdbcRealm

authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy = $authcStrategy

>>>>>>>>>>>>>>>>>>>>> What I tired

# session timeout
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionMode=native
securityManager.sessionManager.globalSessionTimeout = 60000
securityManager.sessionManager = $sessionManager

sessionValidationScheduler = org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler
sessionValidationScheduler.interval = 30000
securityManager.sessionManager.sessionValidationScheduler = $sessionValidationScheduler

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

[urls]
/logout = logout
/css/** = anon
/images/** = anon
/plugins/** = anon
/favicon.ico = anon
/tdf.ico = anon
/Login.html = authc
...
/** = authc, roles[user]
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:0)

您可以保留web.xml原样,因为Shiro与此文件中的配置无关。您的servlet的HttpSession和Shiro HttpServletRequest使用的Session存在差异。它们是完全不同的东西。所以不要被servlet的会话配置和Shiro的会话配置搞糊涂了。在这种情况下,我们让Shiro处理您的会话。

shiro.ini的问题
您正在覆盖您要写入DefaultWebSessionManager的设置:

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager // Define a sessionManager variable
securityManager.sessionMode=native
securityManager.sessionManager.globalSessionTimeout = 60000 // set a securityManager.sessionManager property
securityManager.sessionManager = $sessionManager // override the property by setting the object

您必须先设置对象:

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
securityManager.sessionManager = $sessionManager
securityManager.sessionMode=native
securityManager.sessionManager.globalSessionTimeout = 60000

您不需要ExecutorServiceSessionValidationScheduler,因为DefaultWebSessionManager已经提供了一个valdiator。一个工作示例可能如下所示:

sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
# Session timeout token_ttl_ms = 14 days
sessionManager.globalSessionTimeout = 1209600000
# Session valdiation = 15 minutes
sessionManager.sessionValidationInterval = 900000

securityManager = org.apache.shiro.web.mgt.DefaultWebSecurityManager
securityManager.sessionManager = $sessionManager

<强> DefaultWebSessionManager

DefaultWebSessionManager提供您正在寻找的所有功能(基本上)。当会话在其super上的DefaultWebSessionManager次呼叫onExpiration到期时,会通知其所有听众关于SessionManager中的到期日期。您只需向SessionManager注册SessionListener,然后按其onExpiration方式触发重新加载或重定向即可。也许这种方法非常适合jsp / jspx应用程序 无论如何,请阅读如何在官方文档中注册会话监听器here

替代方法

另一种方法可能是让您的客户端管理会话状态,并通过调用您的服务让它持续检查到期时间。这可以通过计时器或JavaScript中的循环来完成。

注意

org.apache.shiro.authc.credential.Sha256CredentialsMatcher自2010年起被弃用。
直接使用HashedCredentialsMatcher并设置其hashAlgorithmName属性。

答案 1 :(得分:0)

最后,我使用@ ng-idle / core angular package在我的客户端实现了一个超时解决方案:

https://www.npmjs.com/package/@ng-idle/core

https://hackedbychinese.github.io/ng2-idle/

我还使用@ ng-idle / keepalive连续ping服务器并保持活着:

handleIdle(){
  // sets an idle timeout of x seconds, for testing purposes.
 this.idle.setIdle(/*Config.SESSION_IDLE*/ this.sessionIdle);
 // sets a timeout period of y seconds. after x+y seconds of inactivity, the user will be considered timed out.
 this.idle.setTimeout(/*Config.SESSION_TIMEOUT*/ this.sessionTimeout);
 // sets the default interrupts, in this case, things like clicks, scrolls, touches to the document
 this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES);

 this.idle.onIdleEnd.subscribe(() => this.idleState = 'No longer idle.');
 this.idle.onTimeout.subscribe(() => {
   this.idleState = 'Timed out!';
   this.timedOut = true;
 });
 this.idle.onIdleStart.subscribe(() => {
         this.idleState = 'You\'ve gone idle!'
         this.idleModal.open();
     }    
 );
 this.idle.onTimeoutWarning.subscribe((countdown) => {
     this.idleState = 'You\'ve gone idle! Your session will be timed out in ' + countdown + ' seconds!';

     if (countdown == 1){
         window.location.href = "../logout";
     }
 });

 // sets the ping interval to z seconds
 this.keepalive.interval(/*Config.KEEP_ALIVE_INTERVAL*/this.keepAliveInterval);

 this.keepalive.onPing.subscribe(() => {
     this.lastPing = new Date();
     this.resourcesService.ping();
 });

 this.reset(); }