You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shiro会话超时后重定向至登录页的配置问题求助

会话超时自动重定向登录页的Shiro配置问题

我正在用Java+Angular开发Web应用,想要实现会话超时后自动重定向到登录页,现在有两个疑问:

  1. Shiro会自动处理这个重定向逻辑吗?
  2. 如果需要手动实现,正确的配置或代码方式是什么?

我已经尝试了两种方法但都没效果:

  • 在web.xml中配置session-timeout但未生效(目前该配置是注释状态)
  • 修改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>

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 
credentialsMatche

问题排查与解决方案

一、先看你的配置问题

1. web.xml的问题

  • 你注释掉的session-config和error-page,其实和Shiro的会话管理不冲突,但Shiro自身的会话配置优先级更高,就算开启session-timeout也可能被Shiro覆盖,所以核心问题不在这。
  • 另外,error-page是针对JSF的ViewExpiredException,但你用的是Angular+REST后端,这个异常基本不会触发,注释掉也没问题。

2. shiro.ini的问题

一眼就看到你最后一行是credentialsMatche——明显拼写错误!应该是credentialsMatcher(少了个r),而且你只定义了这个凭证匹配器,却没把它绑定到对应的Realm上,这直接导致Shiro认证逻辑异常,所以应用无法登录。

另外,你同时配置了ldapRealm和jdbcRealm,但没明确多Realm的认证策略,这也是潜在隐患:多个Realm共存时,必须告诉Shiro怎么处理认证结果。

二、正确实现会话超时重定向的步骤

1. 修复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 
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher 
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 
# 把凭证匹配器绑定到JDBC Realm(因为JDBC需要校验密码哈希)
jdbcRealm.credentialsMatcher = $credentialsMatcher 

# 配置多Realm认证策略:只要一个Realm认证成功就算登录
authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator
authenticator.authenticationStrategy = org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
securityManager.authenticator = $authenticator
# 把两个Realm添加到SecurityManager
securityManager.realms = $ldapRealm, $jdbcRealm

# 核心:会话超时配置
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
# 设置会话超时时间,单位毫秒,这里是30分钟=1800000ms
sessionManager.globalSessionTimeout = 1800000
# 开启定时清理过期会话
sessionManager.sessionValidationSchedulerEnabled = true
securityManager.sessionManager = $sessionManager

# 登录重定向配置:未认证/会话超时访问受限资源时,自动跳转到登录页
authc.loginUrl = /Login.html

2. 添加Shiro的URL访问规则

在shiro.ini末尾加上[urls]段,定义哪些资源需要认证:

[urls]
# 登录页面允许匿名访问
/Login.html = anon
# Angular入口页和静态资源允许匿名
/index.html = anon
/static/** = anon
# 其他所有资源必须认证后才能访问
/** = authc

3. 前端Angular的配合

因为是单页应用,后端返回的是REST接口,AJAX请求不会自动跳转页面,所以需要在前端统一处理401未授权响应:
可以写一个HTTP拦截器,捕获401状态码后跳转到登录页:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http';
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';
import { Router } from '@angular/router';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private router: Router) {}

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    return next.handle(req).pipe(
      catchError((error: HttpErrorResponse) => {
        if (error.status === 401) {
          // 会话超时或未登录,跳转到登录页
          this.router.navigate(['/login']);
        }
        return throwError(error);
      })
    );
  }
}

4. 测试会话超时

  • 把sessionManager.globalSessionTimeout临时设为60000ms(1分钟)
  • 登录后等待1分钟,刷新页面或发起API请求,验证是否自动跳转到登录页

三、关键知识点

  • Shiro不会完全自动处理所有场景:对于普通HTTP页面请求,配置authc.loginUrl后会自动跳转;但AJAX请求需要前端配合处理401响应。
  • Shiro的会话配置优先级高于web.xml的session-timeout,所以必须在Shiro里设置globalSessionTimeout。
  • 多Realm共存时,一定要明确认证策略,否则会出现认证逻辑混乱。

内容的提问来源于stack exchange,提问作者zbeedatm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:57:15