Title: Keep locale on Spring Security session timeout
Tags: spring;spring-mvc;spring-security
Question: I'm using Spring Security 3.0.2 and I have this config
<security:form-login
login-processing-url="/resources/j_spring_security_check"
login-page="/login"
authentication-failure-handler-ref="authErrorHandler" authentication-success-handler-ref="authCorrectHandler" /&gt;
<security:logout logout-success-url="/index.jsp" invalidate-session="false" /&gt;
<security:remember-me /&gt;
<security:session-management invalid-session-url="/login/sessionExpired" &gt;
<security:concurrency-control max-sessions="1"
error-if-maximum-exceeded="true" /&gt;
</security:session-management&gt;
When I login with a certain locale, all went well but when expiring session, Spring Security clear session and create new anonymous session with locale by default (and go to the login page as expected). The result is the user locale was LOST.
How can I keep the user locale when expiring session in Spring Security 3.0.2?
I'm using localeChangeInterceptor to set the locale, like this:
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"&gt;
<property name="paramName" value="language" /&gt;
</bean&gt;
and SessionLocaleResolver as locale resolver:
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"&gt;
<property name="defaultLocale" value="es" /&gt;
</bean&gt;
EDIT - SOLVED FOR MY NEEDS
I've solved this finally setting a cookie in my own LocaleChangeInterceptor which extends from HandlerInterceptorAdapter, writing this in preHandle method:
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException("No LocaleResolver found.");
}
Cookie mylang = new Cookie("mylang", locale.getLanguage() + "_" + locale.getCountry());
mylang.setMaxAge(86400);
response.addCookie(mylang);
localeResolver.setLocale(request, response, locale);
and then in the /sessionExpired controller point, I'm getting the cookie value:
public String sessionExpired(HttpServletRequest request, HttpServletResponse response, Model model,
@CookieValue(value = "mylang", defaultValue = "es_ES") String myLang) throws Exception {
model.addAttribute("mylang", myLang);
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
StringTokenizer st = new StringTokenizer(myLang, "_");
String language = "";
String country = "";
try {
language = (String) st.nextElement();
country = (String) st.nextElement();
} catch (Exception e) {
throw new Exception("Error locale");
Locale locale = new Locale(language, country);
localeResolver.setLocale(request, response, locale);
return "sessionExpired";
No need to use database as temporal storage in this case.
Comment: Can you post how you are setting locale?

Comment: Logically it does not look like you can use the session to keep track of the locale. The locale is set using a request param `language` which will be cleared with the session. When a new session is created the locale is defaulted to `es` as given by your `localeResolver`. One way I could think is to store user preferences in a DB and retrieve from there on subsequent log-ins.

Comment: You are using the `SessionLocaleResolver` which, obviously stores it in the session. No session no stored locale. If you are ok with cookies use the `CookieLocaleResolver` which persists the choice in a cookie. Else implement your own `LocaleResolver` which stores/retrieves from database.

Comment: updated post showing how I'm setting locale

Comment: Correct, that's what I'm thinking. But I was hoping Spring Security maybe had any mechanism to keep and not destroy the locale.


Here is another answer: Logically it does not look like you can use the session to keep track of the locale. The locale is set using a request param language which will be cleared with the session. When a new session is created the locale is defaulted to es as given by your localeResolver. One way I could think is to store user preferences in a DB and retrieve from there on subsequent log-ins
Also as suggested by @M. Deinum:
If you are ok with cookies use the CookieLocaleResolver which persists the choice in a cookie. Else implement your own LocaleResolver which stores/retrieves from database.
Comment for this answer: I don't know why but CookieLocaleResolver itself doesn't works for me at login time, keep the previous stored locale instead current one. Anyway, session timeout work as expected and keep the locale. Let me check the problem at login time.
Comment for this answer: I've updated the question with a solution working for me. Thanks all for your help :)

Here is another answer: Stumbled upon this old question and just thought of sharing how I got away with my predicament using a Filter (would've preferred an Interceptor but for some reason it annoyingly ain't working for me as of this writing).
public class SessionTimeoutFilter implements Filter {
private String contextPath;
private String language;
@Override
public void init(FilterConfig config) {
contextPath = config.getInitParameter(&quot;context.path&quot;);
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String path = request.getRequestURI();
if (path.equals(contextPath)) { //the index page
request.getSession(true);
chain.doFilter(request, response);
} else {
HttpSession session = request.getSession(false);
if (session != null) {
language = (String) session.getAttribute(&quot;lang&quot;);
chain.doFilter(request, response);
} else {
response.sendRedirect(contextPath + &quot;?timeout=true&amp;lang=&quot; + language);
}
}
And on top of a LocaleChangeInterceptor, I had parameters in my Controller.
@GetMapping(&quot;/&quot;)
public String home(@RequestParam(value = &quot;timeout&quot;, required = false) Boolean timeout,
@RequestParam(value = &quot;lang&quot;, required = false) String language,
HttpServletRequest request, Model model) {
if (Strings.isNotBlank(language)) {
LocaleContextHolder.setLocale(new Locale(language));
} else {
language = LocaleContextHolder.getLocale().getLanguage();
if (BooleanUtils.isTrue(timeout)) {
String message = messageService.getMessage(&quot;error.timeout&quot;, null);
model.addAttribute(&quot;message&quot;, message);
request.getSession().setAttribute(&quot;lang&quot;, language);
return &quot;index&quot;;

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 5, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2014:00:06/20/14', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<spring><spring-mvc><spring-security>', 'Title': 'Keep locale on Spring Security session timeout', 'ViewCount': 2169, 'id': 24327245, 'user_AboutMe': '<p>Project Manager at @Redsys_es Software Engineer with experience in #Linux, #Python, #Android, #PHP, #J2EE and #FLOSS enthusiastic. <a href="http://www.linkedin.com/in/neonigmacdb" rel="nofollow noreferrer">http://www.linkedin.com/in/neonigmacdb</a></p>\n', 'user_AccountId': 1044243.0, 'user_DisplayName': 'Neonigma', 'user_Reputation': 1815.0, 'user_Views': 134.0, 'user_id': 1049572.0}}