发布于2021-12-16 21:48 阅读(1409) 评论(0) 点赞(14) 收藏(5)
我想在会话超时上做一些活动,我使用了 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 方法时,会话的 lastAccessTime 会更新为当前时间。我认为原因是在去 prehandle 方法之前,每个请求都转到我的自定义 UsernamePasswordAuthenticationFilter 的 doget 方法。我还在我的应用程序中使用了 Spring 安全性。
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);
}
}
任何帮助将不胜感激谢谢。
If you are using Spring security then it's better to rely on the session timeout instead of checking the inactive time yourself. Few issues with this approach is - you are implementing security at much deeper level in stack as it should be handled at Filter level which is where Spring security handles it. Secondly as per servlet specs
The session is considered to be accessed when a request that is part of the session is first handled by the servlet container.
Also the session.getLastAccessedTime()
is updated anytime when the request.getSession
is called (atleast this is how it is in Tomcat 7, there could be multiple behaviours as explained here) which can be called at any place - any other Filter configured, Servlet, HandlerInterceptor, Controller. And last but very important - SecurityContextHolder.clearContext()
will remove the SecurityContext
from the current thread ( where it was saved by ThreadLocal
) but it will be still present in the session ( where it will is saved by default) which is not what you actually want.
Another option could be to store the login time in the User Object stored in Spring security context on login and then check for the time and inactivate the session and redirecting to login page afresh.
UPDATE:- There is another easy way in which you can write a custom filter like below and register it before the Spring security filter in web.xml. What we are doing here is saving last access time in session for first visit, then updating the last access time in session on every visit but if it exceeds the inactive time redirect to login page. So basically you are not rely on session object last access time but a user defined variable stored in session. Also we invalidate the current session if inactivity time exceeds. I have tested this filter along with Spring security filters and it works fine. You can do similar thing in an Spring HandlerInterceptor but I feel this kind of check should be implemented at a place even before Spring security gets involved. But it's a choice.
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()");
}
}
作者:黑洞官方问答小能手
链接:http://www.javaheidong.com/blog/article/357393/5e562c649a70edb31ebd/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!