gpt4 book ai didi

java - 如何在 spring mvc 中使用 HandlerInterceptorAdapter 手动处理 session 超时

转载 作者:行者123 更新时间:2023-11-30 06:30:03 26 4
gpt4 key购买 nike

我想在 session 超时时执行一些 Activity ,我使用了 HandlerInterceptorAdapter,如下所示

package com.practice.security;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class SessionHandelerInterceptor extends HandlerInterceptorAdapter{
private static final long MAX_INACTIVE_SESSION_TIME = 5 * 10000;
@Autowired
private HttpSession session;
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {

//long startTime = System.currentTimeMillis();

//request.setAttribute("executionTime", startTime);
if (this.isUserLogged()) {
session = request.getSession();
if (System.currentTimeMillis() - session.getLastAccessedTime()
> MAX_INACTIVE_SESSION_TIME) {

//Do some more activity

SecurityContextHolder.clearContext();
request.logout();
response.sendRedirect("/userLogin/logout");
}
}
return true;
}

private boolean isUserLogged(){
try {
return !SecurityContextHolder.getContext().getAuthentication()
.getName().equals("anonymousUser");
} catch (Exception e) {
return false;
}
}
}

问题是当请求到达拦截器的 preHandle 方法时, session 的 lastAccessTime 会更新为当前时间。我认为原因是在预处理方法之前,每个请求都会转到我的自定义 UsernamePasswordAuthenticationFilter 的 doget 方法。我还在我的应用程序中使用了 Spring security。

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.practice.AppConstant;

public class AuthenticationTokenFilter extends UsernamePasswordAuthenticationFilter {

private Tokenutils tokenUtils;

//@Autowired
//private UserDetailsService userDetailService;

@Override
public void doFilter(ServletRequest request , ServletResponse res , FilterChain chain) throws IOException , ServletException{

tokenUtils=(Tokenutils) WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext()).getBean(Tokenutils.class);

//userDetailService=WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext()).getBean(UserDetailsService.class);

HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
//response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type,"+AppConstant.tokenHeader);

HttpServletRequest httpRequest = (HttpServletRequest)request;
//String authToken=httpRequest.getHeader(AppConstant.tokenHeader);
String authToken=httpRequest.getParameter("XAuthToken");
String userName=this.tokenUtils.getUsernameFromToken(authToken);
if(userName!=null && SecurityContextHolder.getContext().getAuthentication()==null){
//UserDetails userDetails= this.userDetailService.loadUserByUsername(userName);
UserDetails userDetails=new SpringSecurityUser(1L, userName, null, null, null, AuthorityUtils.commaSeparatedStringToAuthorityList(""));
if(this.tokenUtils.validateToken(authToken,userDetails)){
UsernamePasswordAuthenticationToken authentication= new UsernamePasswordAuthenticationToken(userDetails, null,userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, res);
}
}

如有任何帮助,我们将不胜感激,谢谢。

最佳答案

如果您使用 Spring 安全性,那么最好依赖 session 超时,而不是自己检查非 Activity 时间。这种方法的几个问题是 - 您在堆栈中实现更深层次的安全性,因为它应该在过滤器级别处理,这是 Spring 安全性处理它的地方。其次根据 servlet 规范

The session is considered to be accessed when a request that is part of the session is first handled by the servlet container.

此外,session.getLastAccessedTime() 会在调用 request.getSession 时随时更新(至少在 Tomcat 7 中是这样,可能有多种行为)如 here 所解释的那样),可以在任何地方调用 - 任何其他配置的过滤器、Servlet、HandlerInterceptor、 Controller 。最后但非常重要 - SecurityContextHolder.clearContext() 将从当前线程(由 ThreadLocal 保存它)中删除 SecurityContext 但它仍将存在于 session 中(默认情况下会保存在 session 中),这不是您真正想要的。

另一种选择是将登录时间存储在登录时存储在 Spring 安全上下文中的用户对象中,然后检查时间并停用 session 并重新重定向到登录页面。

更新:- 还有另一种简单的方法,您可以编写如下所示的自定义过滤器,并在 web.xml 中的 Spring 安全过滤器之前注册它。我们在这里所做的是保存第一次访问的 session 中的上次访问时间,然后在每次访问时更新 session 中的上次访问时间,但如果超过非 Activity 时间,则重定向到登录页面。所以基本上你不依赖于 session 对象的上次访问时间,而是依赖于存储在 session 中的用户定义的变量。如果不活动时间超过,我们也会使当前 session 无效。我已经测试了这个过滤器和 Spring 安全过滤器,它工作得很好。你可以在 Spring HandlerInterceptor 中做类似的事情,但我觉得这种检查应该在 Spring 安全性介入之前就在某个地方实现。但这是一个选择。

public class InactivityFilter implements Filter {

private static final long MAX_INACTIVE_SESSION_TIME = 5 * 1000;

public void init(FilterConfig config) throws ServletException {
System.out.println("InactivityFilter.init()");
}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;

String requestURI = request.getRequestURI();
System.out.printf("InactivityFilter.doFilter(): requestURI = %s; ", requestURI);

Long firstAccessTime = (Long) request.getSession().getAttribute("lastAccessTime");

if (firstAccessTime == null) {
request.getSession().setAttribute("lastAccessTime", new Date().getTime());
chain.doFilter(req, resp);
}

if (firstAccessTime != null) {
if (System.currentTimeMillis() - firstAccessTime > MAX_INACTIVE_SESSION_TIME) {
request.getSession().invalidate();
response.sendRedirect("the url for login page");
return;
} else {
request.getSession().setAttribute("lastAccessTime", new Date().getTime());
chain.doFilter(req, resp);
}

}

}

public void destroy() {
System.out.println("InactivityFilter.destroy()");
}

}

关于java - 如何在 spring mvc 中使用 HandlerInterceptorAdapter 手动处理 session 超时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46359234/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com