I need to redirect my webapp (Java + angular) to login page when session is timed out. Does shiro do the redirection automatically or shall this be handled by code?
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. I tried updating my shiro.ini, but then couldn't login to my app anymore!
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:
<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 :
[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. There is a difference in the HttpSession
used by the HttpServletRequest
of your servlet and the Shiro Session
. They are completely different things. So don't get confused by the session configuration by the servlet and the one by Shiro. We let Shiro handle your session in this case.
Problems with your shiro.ini
You are overriding the settings you are writing to the 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. 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
The DefaultWebSessionManager provides all the functionality you are looking for out of the box (basically). When a session expires the DefaultWebSessionManager
calls onExpiration
on its super which notifys all its listeners about the expiration in the SessionManager. You simply could register a SessionListener to your SessionManager
and trigger a reload or redirect at its onExpiration
method. Maybe this approach is rather suitable for jsp/jspx applications.
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.
Note
org.apache.shiro.authc.credential.Sha256CredentialsMatcher
is deprecated since 2010.
Use the HashedCredentialsMatcher directly and set its hashAlgorithmName property.