How do you enable LocaleInterceptor to change the

2019-03-20 19:11发布

问题:

Pardon me if this question has been asked before, but I haven't gotten a straight answer that helped me solve my problem. I have a gwt application that I have secured using spring-security. Spring security just authenticates the user and redirects to the gwt application. Now i want the user to be able to change the locale from a link on the login page after which the locale will be stored on a cookie and used in the app.

I have the following configurations, in my applicationContext.xml

<http auto-config="true">
    <intercept-url pattern="/mywebapp/**" access="ROLE_USER"/>
    <intercept-url pattern="/gwt/**" access="ROLE_USER"/>
    <intercept-url pattern="/**/*.html" access="ROLE_USER"/>
    <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <form-login login-page="/login.jsp"/>
</http>
<beans:bean id="userDetailsService"
    class="com.kibet.mywebapp.server.auth.UserDetailsServiceImpl">
</beans:bean>

...
<!-- Application Message Bundle -->
<beans:bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <beans:property name="basename" value="classpath:messages" />
    <beans:property name="defaultEncoding" value="UTF-8"/>
</beans:bean>

<beans:bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <beans:property name="paramName" value="lang" />
</beans:bean>

<beans:bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <beans:property name="defaultLocale" value="pt"/>
</beans:bean>

<beans:bean id="urlMapping"
     class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <beans:property name="interceptors">
    <beans:list>
        <beans:ref bean="localeChangeInterceptor"/>
    </beans:list>
    </beans:property>
    <beans:property name="mappings">
    <beans:value>/login.jsp=userDetailsService</beans:value>
    </beans:property>
</beans:bean>

This doesn't seem to work. I have the locale properties files messages_en.properties, messages_es.properties and messages_pt.properties in my classpath. The only time it works is when I change the browsers default locale. As far as I can tell, the login page is generated by spring-security and the handler mapping cannot intercept the locale change request. If this is the reason how would I go about this? Help is highly appreciated.

Here's my Custom filter code.

public class InternationalizationFilter implements Filter {

@Override
public void destroy() {
    // TODO Auto-generated method stub

}

@Override
public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain filterChain) throws IOException, ServletException {
    String newLocale = request.getParameter("lang");
    if (newLocale != null) {
        Locale locale = StringUtils.parseLocaleString(newLocale
                .toLowerCase());
        LocaleContextHolder.setLocale(locale);
    }
    try {
        filterChain.doFilter(request, response);
    } finally {

        LocaleContextHolder.resetLocaleContext();
    }
}

@Override
public void init(FilterConfig arg0) throws ServletException {

}}

回答1:

The LocaleChangeInterceptor is a part of Spring MVC and that means they don't come in picture in spring security filters. You will have to set locale yourself within the filter chain. Please also see Spring Security/SEC-1527: Internationalize one of the sample applications



回答2:

Thanks @Ritesh for give the answer. You give me a idea to handle this problem. I worked around it on a further way:

public class InternationalizationFilter extends OncePerRequestFilter {
  private Logger log=Logger.getLogger(InternationalizationFilter.class);
  private String localeParam="lang";
  private LocaleResolver localeResolver;

  public InternationalizationFilter(String localeParam, LocaleResolver localeResolver) {
    this.localeParam = localeParam;
    this.localeResolver = localeResolver;
  }

  @Override
  public void destroy() {
    // TODO Auto-generated method stub

  }

  @Override
  protected void doFilterInternal(
      final HttpServletRequest request,
      final HttpServletResponse response,
      final FilterChain filterChain)
      throws ServletException, IOException {
    if (localeResolver == null) {
      throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
    }
    else{
      final String newLocale = request.getParameter(localeParam);
      if (newLocale != null) {
        final Locale locale = StringUtils.parseLocaleString(newLocale.toLowerCase());
        LocaleContextHolder.setLocale(locale);
        LocaleEditor localeEditor = new LocaleEditor();
        localeEditor.setAsText(newLocale);
        localeResolver.setLocale(request, response, (Locale) localeEditor.getValue());
        log.debug("change locale to "+
            locale.getLanguage()+"_"+locale.getCountry()+
            " at Thread"+Thread.currentThread().getId());
      }
      else{
        final Locale locale=localeResolver.resolveLocale(request);
        LocaleContextHolder.setLocale(locale);
        log.debug("restore locale to "+
            locale.getLanguage()+"_"+locale.getCountry()+
            " at Thread"+Thread.currentThread().getId());
      }
      try {
        filterChain.doFilter(request, response);
      } finally {
        LocaleContextHolder.resetLocaleContext();
      }
    }
  }

}

With declared the localChangeInterceptor and localeResolver in mvc config file. So we can change locale with request param "lang":

  <mvc:interceptors>
    <bean id="localChangeInterceptor"
          class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
      <property name="paramName" value="lang"/>
    </bean>
  </mvc:interceptors>


  <!--localeResolver-->
  <bean id="localeResolver"
        class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <!--<property name="cookieDomain" value=""/>-->
    <property name="defaultLocale" value="zh"/>
  </bean>

In the security config file,I made a i18nFilter and added it to the Filter Chain:

  <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
    <security:filter-chain-map path-type="ant">
      <security:filter-chain pattern="/**/*.css" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/**/*.jpg" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/**/*.png" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/**/*.gif" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/**/*.js" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/**/*.cur" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/**/*.swf" filters="
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/login" filters="
          i18nFilter,
          securityContextPersistenceFilter,
          exceptionTranslationFilter"/>
      <security:filter-chain pattern="/checkin" filters="
          i18nFilter,
          securityContextPersistenceFilter,
          authenticationFilter"/>
      <security:filter-chain pattern="/**" filters="
           i18nFilter,
           securityContextPersistenceFilter,
           authenticationFilter,
           logoutFilter,
           anonymousAuthenticationFilter,
           exceptionTranslationFilter,
           filterSecurityInterceptor" />

    </security:filter-chain-map>
  </bean> 



<bean id="i18nFilter" class="com.bjinfotech.filter.InternationalizationFilter">
    <constructor-arg name="localeParam" value="lang"/>
    <constructor-arg name="localeResolver" ref="localeResolver"/>
  </bean>

with localChangeInterceptor & localeResolver,I can change locale and save locale into session or cookie.

under localeResolver's help,InternationalizationFilter could store/restore locale and make change to LocaleContextHolder's locale.



回答3:

First the key is the LocaleResolver and forget the interceptor.

Just create a bean that implement this interface to resolve the locale from where you save it, as example from an attribute of the request.

public class LocaleResolverImpl implements LocaleResolver {

    public LocaleResolverImpl() {
    }

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        Locale r = (Locale) request.getAttribute("localeObject");
        return r == null ? request.getLocale() : r;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}