Изменить язык при входе - PullRequest
       15

Изменить язык при входе

13 голосов
/ 16 декабря 2011

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

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

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

Ответы [ 3 ]

9 голосов
/ 10 января 2012

Лучшее решение, которое мне удалось найти, - это обработать его в 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>
2 голосов
/ 04 января 2012

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

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

Чтобы получить доступ к вашему localeResolver (или другим компонентам) из вашего фильтра, выполните что-то вроде этого в методе 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, выполните любую бизнес-логику, чтобы определить локаль этого пользователя, и вызовите 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 голосов
/ 04 января 2012

Мой текущий обходной путь работает таким образом (но все еще является хаком, потому что он не запускается процессом входа в систему):

У меня есть Spring HandlerInterceptor, который перехватывает каждый запрос.Он всегда проверяет, есть ли уже в сеансе пользователя флаг (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE), который указывает, что локальный уже обновлен.Если такого флага нет, то перехватчик проверяет, принадлежит ли запрос аутентифицированному пользователю.Если это аутентифицированный пользователь, то он обновляет локальный код localResolver и устанавливает флаг (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) в сеансе

Этот материал флага сеанса необходим, потому что локальный должен быть изменен только сразу послеавторизоваться.Таким образом, позже пользователь может снова изменить локальное через обычный перехватчик локального изменения.

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);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...