【问题标题】:refresh cookie on each request in spring在春季的每个请求上刷新 cookie
【发布时间】:2021-06-08 17:25:56
【问题描述】:

我有一个应用程序,其中我将会话超时设置为 1 小时。但我不希望如果用户关闭浏览器并再次打开它,他必须再次登录。为此,我需要一种方法来以某种方式刷新每个请求的 cookie 到期时间。

我正在使用带有弹簧安全性的弹簧靴。我怎样才能实现这个功能?

【问题讨论】:

  • 您好,最有效的方法是使用Spring Session。它将加载请求过滤器并用数据库存储的会话替换原始 cookie 和会话。我建议使用 Spring Session 的 redis 或 jdbc 实现。 Hele 是official manual,这里是github repo
  • @AleksandrsRudzitis 您的评论有何帮助? cookie 过期后的 AFAIK 会话也随着 Spring Session 消失。问题是关于延长 cookie 超时时间。
  • 为此,我需要一种方法来以某种方式刷新每个请求的 cookie 到期时间。 AFAIR 服务器已经这样做了。如果您使用应用程序超过 1 小时,应该没有问题。如果超过 1 小时没有提出请求,就会出现问题。

标签: spring spring-boot spring-security


【解决方案1】:

我已经使用拦截器解决了这个问题。这个想法是拦截http请求并修改jsessionid cookie并将到期时间设置为您想要的任何值。这将允许 cookie 在重新打开后被浏览器重用。默认情况下,jsessionid cookie 的 max age 等于 -1,这意味着它的 cookie 会在浏览器关闭后立即过期。

public class CookieExpiryRefresher extends HandlerInterceptorAdapter {


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, //
                           Object handler, ModelAndView modelAndView) throws Exception {


        Cookie[] cookies = request.getCookies();

        for (Cookie cookie : cookies){
            if (cookie.getName().contentEquals("JSESSIONID")){
                if (cookie.getValue().contentEquals(request.getSession().getId())){
                    cookie.setMaxAge(60*60*5);
                    cookie.setPath("/");
                    response.addCookie(cookie);
                    break;
                }
            }
        }

    }

}

并且这个拦截器可以注册如下:

@Component
public class WebMvcConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addInterceptors(InterceptorRegistry registry){

        registry.addInterceptor(new CookieExpiryRefresher());
    }
}

【讨论】:

  • 您好,我也面临同样的问题,但您的解决方案似乎只是一个替代方案。我是,有正确创建会话 cookie 的功能(查看最大年龄、路径、jvm,...),我真的很想使用它(执行两次可能会导致麻烦)。 Sprign 真的没有功能来实现这个吗?如果没有,是否可以使用 DefaultCookieSerializer 以某种方式更新 cookie 到期日期?
【解决方案2】:

Baeldung 有一个使用过滤器的解决方案。 @https://www.baeldung.com/spring-security-session

public class SessionFilter implements Filter {
@Override
public void doFilter(
  ServletRequest request, ServletResponse response, FilterChain chain)
  throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    Cookie[] allCookies = req.getCookies();
    if (allCookies != null) {
        Cookie session = 
          Arrays.stream(allCookies).filter(x -> x.getName().equals("JSESSIONID"))
                .findFirst().orElse(null);

        if (session != null) {
            session.setHttpOnly(true);
            session.setSecure(true);
            res.addCookie(session);
        }
    }
    chain.doFilter(req, res);
}

}

【讨论】:

    【解决方案3】:

    你只能在拦截器的preHandle中创建、更新和删除cookie。

    如果你想在控制器被调用后添加一个cookie,那么必须使用ControllerAdvice

    @ControllerAdvice
    public class CookieAdvice implements ResponseBodyAdvice<Object>  {
    
    @Override
    public boolean supports(MethodParameter returnType,
            Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType,
            MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType,
            ServerHttpRequest request, ServerHttpResponse response) {
        Cookie cookie = new Cookie("cookieName", cookieValue);
        ServletServerHttpResponse resp = (ServletServerHttpResponse)response;
        resp.getServletResponse().addCookie(cookie);
        return body;
    }
    

    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-02
      • 2020-11-26
      • 2017-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-28
      • 1970-01-01
      相关资源
      最近更新 更多