2011-12-16 3 views
10

Я хочу изменить локаль после входа в локаль по умолчанию, хранящуюся в учетной записи пользователя Spring MVC Application (3.0) с Spring Security (3.0).Изменить язык при входе в систему

Я уже использую LocaleChangeInterceptor, так что (не вошел в систему, а также вошел в систему) пользователь может изменить свой язык (по умолчанию из заголовка accept). Но клиент действительно хочет, чтобы учетная запись была выполнена по умолчанию.

Итак, мой вопрос в том, что было бы лучшим способом изменить языковой стандарт после входа в систему, или уже есть встроенная функциональность в Spring/Security?

+1

Поскольку у вас уже есть механизм, чтобы изменить региональные настройки, вы можете создать собственный [ 'AuthenticationSuccessHandler'] (http://static.springsource.org/spring- security/site/docs/3.0.x/apidocs/org/springframework/security/web/authentication/AuthenticationSuccessHandler.html), чтобы перехватить логин и изменить локаль на основе предпочтений пользователя. Проверьте [здесь] (http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity-single.html#nsa-form-login) и [здесь] (http: // stackoverflow.com/a/6612634/468508) для получения дополнительной информации. – bluefoot

ответ

8

Лучшее решение, которое я смог найти, это обработать это в 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();  
} 

фрагменты конфигурации:

<security:http ...> 
    <security:custom-filter ref="usernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER"/> 
</security:http> 

<bean id="usernamePasswordAuthenticationFilter" 
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
    <property name="filterProcessesUrl" value="/login/j_spring_security_check"/> 
    <property name="authenticationManager" ref="authenticationManager"/> 
    <property name="authenticationFailureHandler"> 
     <bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> 
      <property name="defaultFailureUrl" value="/login?login_error=t"/> 
     </bean> 
    </property> 
    <property name="authenticationSuccessHandler"> 
     <bean class="LocaleSettingAuthenticationSuccessHandler"> 
    </property> 
</bean> 
+0

спасибо: эта идея будет работать, я немного изменил ее для использования событий (что в отличие от InteractiveAuthenticationSuccessEvent и AuthenticationSuccessEvent содержит объект Request and Reponse) – Ralph

+0

Я добавил фрагменты конфигурации для полноты, чтобы указать, где и как «authenticationSuccessHandler» 'можно установить. - Если вам это не нравится, то удалите часть из ответа - извините, что я отредактировал ответ yor, но это был текст для комментария. – Ralph

+0

, похоже, больше не работают, localeResolver allway null –

2

Используйте SessionLocaleResolver и создайте его как фасоль под названием «localeResolver». Этот LocaleResolver разрешит локали, предварительно проверив локаль по умолчанию, с которой был создан резольвер. Если это значение равно null, оно проверяет, сохранен ли языковой стандарт в сеансе, и если это значение равно null, он установит локаль сеанса на основе заголовка Accept-Language в запросе.

После входа пользователя вы можете вызвать localeResolver.setLocale, чтобы сохранить локаль для сеанса для вас, вы можете сделать это в фильтре сервлета (обязательно определите его в своем web.xml ПОСЛЕ вашей весенней безопасности фильтр).

Чтобы получить доступ к localeResolver (или другие бобы) из вашего фильтра, сделать что-то подобное в методе инициализации:

@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, выполните любую бизнес-логику, чтобы определить эту локаль пользователя, и вызовите setLocale в LocaleResolver.

Лично я не хочу, чтобы 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; 
    } 

} 
+0

Ключевая проблема заключается не в том, какой метод следует вызывать для изменения локального. Ключевой проблемой является запуск какого-либо метода после входа в систему (который имеет доступ к данным для входа (для имени пользователя) и Local Resolver для изменения локального). – Ralph

+0

Я обновил ответ выше. – aweigold

+0

Извините, но это не решает проблему. Он не запускает процесс после входа в систему. Фильтр изменит локальный пользователь с каждым запросом после входа пользователя. Это не то, о чем меня просят: я использую LocaleChangeInterceptor, это означает, что пользователь может изменить свою регистрационную независимость от любого значения по умолчанию, локальный пользовательский локальный только по умолчанию - пользователь должен иметь возможность изменить его позже на этом перехватчике. --- В любом случае, я уже реализовал такое решение (с использованием перехватчика Spring вместо ServletFilter), но это взломать. – Ralph

0

Мой текущий workarround работает следующим образом (но все еще хак, потому что это не вызвано логину процесс):

У меня есть Handler HandlerInterceptor, который перехватывает каждый запрос. Он проверяет всегда, если в сеансе пользователей уже есть флаг (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE), который указывает, что локальный файл уже обновлен. Если такого флага нет, тогда перехватчик проверяет, принадлежит ли запрос аутентифицированному пользователю. Если аутентифицированный пользователь, то он обновляет локальный хотя 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); 
     } 
    } 
} 
Смежные вопросы