简体   繁体   English

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

[英]Shiro - redirect to login page after session timeout

I need to redirect my webapp (Java + angular) to login page when session is timed out.当会话超时时,我需要将我的 webapp(Java + angular)重定向到登录页面。 Does shiro do the redirection automatically or shall this be handled by code? shiro 是自动进行重定向还是由代码处理?

I tried several hacks but didn't work for me.我尝试了几种黑客方法,但对我没有用。 I tried adding session timeout to my web.xml but it simply didn't take affect.我尝试将会话超时添加到我的 web.xml,但它根本没有生效。 I tried updating my shiro.ini, but then couldn't login to my app anymore!我尝试更新我的 shiro.ini,但后来无法再登录我的应用程序了!

Can you please help to find what's wrong in these files or advice what sould be done in such a case.您能否帮助找出这些文件中的问题或建议在这种情况下应该做什么。

Thanks in advance.提前致谢。

web.xml:网页.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>

shiro.ini : shiro.ini:

 [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]

You can leave your web.xml as it is since Shiro has nothing to do with the configruation in this file.您可以保留您的web.xml ,因为 Shiro 与此文件中的配置无关。 There is a difference in the HttpSession used by the HttpServletRequest of your servlet and the Shiro Session . Servlet 的HttpServletRequest和 Shiro Session使用的HttpSession有所不同。 They are completely different things.它们是完全不同的东西。 So don't get confused by the session configuration by the servlet and the one by Shiro.所以不要被 servlet 的会话配置和 Shiro 的会话配置所迷惑。 We let Shiro handle your session in this case.在这种情况下,我们让 Shiro 处理您的会话。

Problems with your shiro.ini shiro.ini 的问题
You are overriding the settings you are writing to the DefaultWebSessionManager :您正在覆盖您正在写入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

You have to set the object first:您必须先设置对象:

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

You don't need the ExecutorServiceSessionValidationScheduler since a valdiator is provided by the DefaultWebSessionManager already.您不需要ExecutorServiceSessionValidationScheduler ,因为DefaultWebSessionManager已经提供了验证器。 A working example could look like the following:一个工作示例可能如下所示:

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

The DefaultWebSessionManager provides all the functionality you are looking for out of the box (basically). DefaultWebSessionManager提供了您正在寻找的所有开箱即用的功能(基本上)。 When a session expires the DefaultWebSessionManager calls onExpiration on its super which notifys all its listeners about the expiration in the SessionManager .当会话过期时, DefaultWebSessionManager会在其super上调用onExpiration ,它会通知其所有侦听器有关SessionManager中的过期。 You simply could register a SessionListener to your SessionManager and trigger a reload or redirect at its onExpiration method.您只需将SessionListener注册到SessionManager并在其onExpiration方法中触发重新加载或重定向。 Maybe this approach is rather suitable for jsp/jspx applications.也许这种方法比较适合 jsp/jspx 应用程序。
Anyway, read how to register a session listener here in the official docs.无论如何,请在官方文档中阅读如何在此处注册会话侦听器。

Alternative approach替代方法

A different approach could be to have your client manage the session state and let it continuously check for expiration by calling your service.另一种方法可能是让您的客户端管理会话状态,并通过调用您的服务让其不断检查是否过期。 This could be done by a timer or in a loop in JavaScript.这可以通过计时器或 JavaScript 循环来完成。

Note笔记

org.apache.shiro.authc.credential.Sha256CredentialsMatcher is deprecated since 2010. org.apache.shiro.authc.credential.Sha256CredentialsMatcher自 2010 年起已弃用。
Use the HashedCredentialsMatcher directly and set its hashAlgorithmName property.直接使用HashedCredentialsMatcher并设置其 hashAlgorithmName 属性。

At the end I implemented a time out solution on my client side using @ng-idle/core angular package:最后,我使用@ng-idle/core angular 包在客户端实现了超时解决方案:

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

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

I used the @ng-idle/keepalive as well to ping the server continuously and keep it alive:我也使用了@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(); }

Just increase the globalSessionTimeout只需增加globalSessionTimeout

The path is WEB-INF/classes/shiro.ini路径是WEB-INF/classes/shiro.ini

sessionManager.globalSessionTimeout = 18000000

It will make the session last longer.这将使会话持续更长时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM