使用自定义Spring MVC的HandlerInterceptor来管理会话

2023/05/17

1. 简介

在本教程中,我们将重点关注 Spring MVC HandlerInterceptor。

更具体地说,我们将展示使用拦截器的更高级用例——我们将通过设置自定义计数器和手动跟踪会话来模拟会话超时逻辑。

如果想了解 Spring 中HandlerInterceptor 的基础知识,请查看这篇文章

2.Maven依赖

为了使用拦截器,需要在pom.xml文件的依赖项部分中包含以下部分:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.3.13</version>
</dependency>Copy
最新版本可以在[这里](https://search.maven.org/classic/#search ga 1 a%3A”spring-web”)找到。此依赖项仅涵盖 Spring Web,因此不要忘记为完整(最小)Web 应用程序添加 s pring-core和spring-context。

3. 会话超时的自定义实现

在此示例中,我们将为系统中的用户配置最长不活动时间。在那之后,他们将自动从应用程序中注销。

这个逻辑只是一个概念证明——我们当然可以使用会话超时轻松实现相同的结果——但结果不是这里的重点,拦截器的使用才是。

因此,我们要确保如果用户不活跃,会话将失效。例如,如果用户忘记注销,非活动时间计数器将阻止未经授权的用户访问该帐户。为此,我们需要为非活动时间设置常量:

private static final long MAX_INACTIVE_SESSION_TIME = 5  10000;

出于测试目的,我们将其设置为 50 秒;别忘了,它是以毫秒计算的。

现在,我们需要跟踪应用程序中的每个会话,因此我们需要包含这个 Spring 接口:

@Autowired
private HttpSession session;

让我们继续使用preHandle()方法。

3.1。预句柄()

在此方法中,我们将包括以下操作:

  • 设置计时器以检查请求的处理时间
  • 检查用户是否登录(使用本文中的UserInterceptor方法)
  • 自动注销,如果用户的非活动会话时间超过最大允许值

让我们看一下实现:

@Override
public boolean preHandle(
  HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
    log.info("Pre handle method - check handling start time");
    long startTime = System.currentTimeMillis();
    request.setAttribute("executionTime", startTime);
}

在这部分代码中,我们设置了处理执行的开始时间。从这一刻起,我们将计算完成每个请求处理的秒数。在下一部分中,我们将提供会话时间的逻辑,前提是有人在他的 HTTP 会话期间登录:

if (UserInterceptor.isUserLogged()) {
    session = request.getSession();
    log.info("Time since last request in this session: {} ms",
      System.currentTimeMillis() - request.getSession().getLastAccessedTime());
    if (System.currentTimeMillis() - session.getLastAccessedTime()
      > MAX_INACTIVE_SESSION_TIME) {
        log.warn("Logging out, due to inactive session");
        SecurityContextHolder.clearContext();
        request.logout();
        response.sendRedirect("/spring-rest-full/logout");
    }
}
return true;

首先,我们需要从请求中获取会话。

接下来,我们做一些控制台日志记录,关于谁登录,以及已经过去了多长时间,因为用户在我们的应用程序中执行了任何操作。我们可以使用session.getLastAccessedTime()来获取此信息,从当前时间中减去它并与我们的MAX_INACTIVE_SESSION_TIME 进行比较。

如果时间超过我们允许的时间,我们清除上下文,注销请求,然后(可选)发送重定向作为对默认注销视图的响应,默认注销视图在 Spring Security 配置文件中声明。

为了完成处理时间的计数器示例,我们还实现了 postHandle()方法,该方法将在下一小节中介绍。

3.2. 后处理()

这个方法只是为了获取信息,处理当前请求需要多长时间。正如在前面的代码片段中看到的,我们在 Spring 模型中设置了executionTime 。现在是时候使用它了:

@Override
public void postHandle(
  HttpServletRequest request, 
  HttpServletResponse response,
  Object handler, 
  ModelAndView model) throws Exception {
    log.info("Post handle method - check execution time of handling");
    long startTime = (Long) request.getAttribute("executionTime");
    log.info("Execution time for handling the request was: {} ms",
      System.currentTimeMillis() - startTime);
}

实现很简单——我们检查执行时间并从当前系统时间中减去它。只要记住将模型的值转换为long。

现在我们可以正确记录执行时间。

4.拦截器的配置

要将我们新创建的拦截器添加到 Spring 配置中,我们需要覆盖实现 WebMvcConfigurer 的WebConfig类中的 addInterceptors()方法:

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new SessionTimerInterceptor());
}

我们可以通过编辑我们的 XML Spring 配置文件来实现相同的配置:

<mvc:interceptors>
    <bean id="sessionTimerInterceptor" class="com.baeldung.web.interceptor.SessionTimerInterceptor"/>
</mvc:interceptors>

此外,我们需要添加监听器,以便自动创建ApplicationContext:

public class ListenerConfig implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext sc) throws ServletException {
        sc.addListener(new RequestContextListener());
    }
}

5. 总结

本教程展示了如何使用 Spring MVC 的HandlerInterceptor拦截 Web 请求,以便手动进行会话管理/超时。

像往常一样,所有示例和配置都可以在GitHub上找到。

5.1。系列文章

该系列的所有文章:

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章