登录时更改区域设置

我想在登录到使用Spring Security(3.0)的用户帐户Spring MVC Application(3.0)中存储的默认语言环境后更改语言环境。

我已经使用了LocaleChangeInterceptor因此(未登录,以及登录)用户可以更改其语言环境(默认来自accept标头)。 但客户真的希望该帐户具体默认。

所以我的问题是,登录后更改语言环境的最佳方法是什么,或者Spring / Security中是否已经有一些内置function?

我能找到的最佳解决方案是在AuthenticationSuccessHandler中处理这个问题。

以下是我为创业公司编写的一些代码:

 public class LocaleSettingAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { @Resource private LocaleResolver localeResolver; @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { setLocale(authentication, request, response); super.onAuthenticationSuccess(request, response, authentication); } protected void setLocale(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { if (authentication != null) { Object principal = authentication.getPrincipal(); if (principal instanceof LocaleProvider) { LocaleProvider localeProvider = (LocaleProvider) principal; Locale providedLocale = localeProvider.getLocale(); localeResolver.setLocale(request, response, providedLocale); } } } } 

并且您的主要课程应提供以下界面。 这不是必需的,但我正在使用它,因为我有多个对象能够为会话提供区域设置。

 public interface LocaleProvider { Locale getLocale(); } 

配置片段:

                

使用SessionLocaleResolver ,并将其构造为名为“localeResolver”的bean。 此LocaleResolver将首先检查构造解析程序的默认语言环境来解析语言环境。 如果它为null,它将检查区域设置是否已存储在会话中,如果该区域设置为null,则它将根据请求中的Accept-Language标头设置会话区域设置。

用户登录后,您可以调用localeResolver.setLocale将语言环境存储到会话中,您可以在servletfilter中执行此操作(确保在弹簧安全filter之后在web.xml中定义)。

要从filter访问localeResolver(或其他bean),请在init方法中执行以下操作:

 @Override public void init(FilterConfig fc) throws ServletException { ServletContext servletContext = fc.getServletContext(); ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext); this.localeResolver = context.getBean(SessionLocaleResolver.class); } 

然后在doFilterMethod中,您应该能够将ServletRequest转换为HttpServletRequest,调用getRemoteUser,执行任何业务逻辑以定义该用户的语言环境,并在LocaleResolver上调用setLocale。

就个人而言,我并不关心SessionLocaleResolver首先使用默认本地(我更喜欢最后一个),但是它很容易扩展和覆盖。 如果您有兴趣检查会话,那么请求,然后是默认请求,使用以下内容:

 import org.springframework.stereotype.Component; import org.springframework.web.util.WebUtils; import javax.servlet.http.HttpServletRequest; import java.util.Locale; // The Spring SessionLocaleResolver loads the default locale prior // to the requests locale, we want the reverse. @Component("localeResolver") public class SessionLocaleResolver extends org.springframework.web.servlet.i18n.SessionLocaleResolver{ public SessionLocaleResolver(){ //TODO: make this configurable this.setDefaultLocale(new Locale("en", "US")); } @Override public Locale resolveLocale(HttpServletRequest request) { Locale locale = (Locale) WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME); if (locale == null) { locale = determineDefaultLocale(request); } return locale; } @Override protected Locale determineDefaultLocale(HttpServletRequest request) { Locale defaultLocale = request.getLocale(); if (defaultLocale == null) { defaultLocale = getDefaultLocale(); } return defaultLocale; } } 

我当前的workarround以这种方式工作(但仍然是一个hack,因为它不是由登录过程触发的):

我有一个Spring HandlerInterceptor来拦截每个请求。 它始终检查用户会话中是否已存在标志( LOCALE_ALREADY_SET_SESSION_ATTRIBUTE ),表明本地已更新。 如果没有这样的标志,则拦截器检查请求是否属于经过身份validation的用户。 如果它是经过身份validation的用户,则它会通过localResolver更新本地并在会话中设置标志( LOCALE_ALREADY_SET_SESSION_ATTRIBUTE

需要此会话标志,因为登录后必须仅更改本地的direclty。 所以稍后用户可以通过正常的本地更改拦截器再次更改本地。

 public class LocalChangeUserInterceptor extends HandlerInterceptorAdapter { /** Session key, used to mark if the local is set. */ private static final String LOCALE_ALREADY_SET_SESSION_ATTRIBUTE = "LocalChangeUserInterceptor.localeAlreadySet"; /** The locale resolver. */ @Resource private LocaleResolver localeResolver; @Resource private UserService userService; @Override public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception { if (!isLocaleAlreadySet(request)) { User currentAuthenticatedUser = getCurrentUserOrNull(); if (currentAuthenticatedUser != null) { this.localeResolver.setLocale(request, response, currentAuthenticatedUser.getLocale()); request.getSession().setAttribute(LOCALE_ALREADY_SET_SESSION_ATTRIBUTE, "true"); } } return true; } /** * Check if there is an session attribute that states that the local is already set once. * @param request the request * @return true, if is locale already set */ private boolean isLocaleAlreadySet(final HttpServletRequest request) { HttpSession sessionOrNull = request.getSession(false); return ((sessionOrNull != null) && (sessionOrNull.getAttribute(LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) != null)); } /** * Get the current user or null if there is no current user. * @return the current user */ public User getCurrentUserOrNull() { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if ((authentication == null) || (authentication instanceof AnonymousAuthenticationToken)) { return null; } else { return this.userService.getUser(authentication); } } }