i need to change locale settings after successful Authentication.
LocaleResolver:
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lng" />
</bean>
<bean id="localeResolver"
class="web.MyLocaleResolver">
</bean>
public class MyLocaleResolver extends AbstractLocaleResolver {
private Locale default = Locale.ENGLISH;
@Override
public Locale resolveLocale(HttpServletRequest hsr) {
return this.default;
}
@Override
public void setLocale(HttpServletRequest hsr, HttpServletResponse hsr1, Locale default) {
this.default = default;
}
}
Security:
<form-login login-page="/login"
authentication-success-handler- ref="MySuccessAuthHandler"/>
<beans:bean id="MySuccessAuthHandler" class="web.MySuccessfulAuthenticationHandler">
<beans:property name="defaultTargetUrl" value="/index.htm"></beans:property>
</beans:bean>
public class MySuccessfulAuthenticationHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
super.onAuthenticationSuccess(request, response, authentication);
RequestContextUtils.getLocaleResolver(request).setLocale(request, response, Locale.ENGLISH);
}
}
When i try to set locale by RequestContextUtils
i get NullPointer Exception.
LocaleResolver
is exposed in request context by DispatcherServlet
, whereas AuthenticationSuccessHandler
is fired before request enters DispatcherServlet
(actually, request that fired SavedRequestAwareAuthenticationSuccessHandler
never enters DispatcherServlet
, because this handler performs a redirect).
Thus, you cannot access LocaleResolver
via RequestContextUtils
in this case. You can try to inject LocaleResolver
into your AuthenticationSuccessHandler
explicitly, for example, with autowiring.
Even though the DispatcherServlet isn't normally reached when using Spring Security, you can add the RequestContextFilter BEFORE your security filter chain which exposes all the request attributes like the localeResolver.
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Even though this should make your example work. For other people: another option is to use WebApplicationContextUtils.getWebApplicationContext(ServletContext)
passing it the ServletContext that is available in the HttpServletRequest
The solution from Kafkaesque is not complete.
But even spring security documentation is wrong:
The LocaleContextHolder needs to be set up to contain the correct
Locale before the filters are called. You can either do this in a
filter yourself (which must come before the Spring Security filters in
web.xml) or you can use Spring's RequestContextFilter.
see https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#localization
You can not use RequestContextFilter
as this filter is not aware of any LocaleResolver
inside your applicationContext. It just uses the Locale from request.getLocale()
which is the Accept-Language
Header.
If you want to use your own LocaleResolver in this filter you need to write your own:
@Component
public class LocaleRequestContextFilter extends OncePerRequestFilter
{
// basiert auf RequestContextFilter
@Inject
private LocaleResolver localeResolver;
@Override
protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException
{
ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
initContextHolders(request, attributes);
try
{
filterChain.doFilter(request, response);
}
finally
{
resetContextHolders();
attributes.requestCompleted();
}
}
private void initContextHolders ( HttpServletRequest request, ServletRequestAttributes requestAttributes )
{
LocaleContextHolder.setLocaleContext(buildLocaleContext(request));
RequestContextHolder.setRequestAttributes(requestAttributes, false);
}
private LocaleContext buildLocaleContext ( final HttpServletRequest request )
{
request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, localeResolver);
if (this.localeResolver instanceof LocaleContextResolver)
{
return ( (LocaleContextResolver) this.localeResolver ).resolveLocaleContext(request);
}
else
{
return new LocaleContext()
{
@Override
public Locale getLocale ( )
{
return localeResolver.resolveLocale(request);
}
};
}
}
private void resetContextHolders ( )
{
LocaleContextHolder.resetLocaleContext();
RequestContextHolder.resetRequestAttributes();
}
}
and then configure your web.xml
<filter>
<filter-name>localeRequestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>localeRequestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>