登录时更改区域设置

我想在登录后将区域设置更改为存储在具有Spring Security(3.0)的用户帐户Spring MVC应用程序(3.0)中的默认区域设置。

我已经使用了 so a (未登录,以及已登录) 用户可以更改其区域设置(默认来自 accept 标头)。但客户确实希望该帐户特定的默认值。LocaleChangeInterceptor

所以我的问题是,登录后更改区域设置的最佳方法是什么,或者Spring/Security中已经有一些内置功能吗?


答案 1

我能找到的最佳解决方案是在身份验证成功处理程序中处理此问题。

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

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

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

用户登录后,您可以调用 localeResolver.setLocale 为您存储会话的区域设置,您可以在 servlet 过滤器中执行此操作(请务必在 Web 中定义它.xml在 spring 安全过滤器之后)。

要从过滤器访问您的区域设置解析器(或其他 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;
    }

}

推荐