I am using Spring Session 1.2.0.RELEASE on a Spring Boot Project. This is packaged as a war and deployed on Tomcat 8.
I have followed Spring Session documentation and configured it properly. The problem is that the entry point to the application is a controller that sets some value on session but the SESSION cookie is not sent to the browser.
Debugging I see that:
org.springframework.session.web.http.CookieHttpSessionStrategy.onNewSession()
tries to write the cookie:
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, cookieValue));
org.springframework.session.web.http.DefaultCookieSerializer.writeCookieValue()
sets the cookie in the response:
response.addCookie(sessionCookie);
The cookie isn't actually written. The underlying response object is org.apache.catalina.core.ApplicationHttpResponse
. Its addCookie()
method is:
/**
* Disallow <code>addCookie()</code> calls on an included response.
* @param cookie The new cookie
*/
@Override
public void addCookie(Cookie cookie) {
if (!included)
((HttpServletResponse) getResponse()).addCookie(cookie);
}
The problem is that included
attribute, which at some point is set true, preventing the cookie from being added.
This happens when the jsp (using tiles) is being serviced:
UPDATE:
This is the moment when the response is being marked as included (when standard.jsp tiles layout is inserting an attribute:
<tiles:insertAttribute name="header" ignore="false"/>
To work around this problem I ended up creating a filter to enforce the creation of the session.
As seen, the first call to the controller didn't add the cookie because during the Tiles-JSP rendering the response was already marked as included. What I do is forcing the creation of the session in the filter and redirecting asking the very same requestURI. This way, since the call doesn't involve a tiles rendering the cookie is created and can be used right away in the next calls.
@Bean
@ConditionalOnExpression("${sessionEnforcerFilter.enabled:true}")
public FilterRegistrationBean sessionEnforcerFilter(){
logger.info("Registering sessionEnforcerFilter");
FilterRegistrationBean frb = new FilterRegistrationBean();
frb.setName("sessionEnforcerFilter");
frb.setFilter(new SessionEnforcerFilter());
frb.setUrlPatterns(Arrays.asList(new String[]{"/*"}));
return frb;
}
public class SessionEnforcerFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
if(httpServletRequest.getSession(false)==null){
logger.debug("sessionEnforcerFilter.doFilter () - Session is null - forcing its creation");
httpServletRequest.getSession();
String requestURI = httpServletRequest.getRequestURI();
logger.debug("sessionEnforcerFilter.doFilter () - Repeating request [{}]", requestURI);
httpServletResponse.sendRedirect(requestURI);
}else{
chain.doFilter(httpServletRequest, response);
}
}
@Override
public void destroy() {}
}