Spring security + LocaleResolver

2019-05-11 13:07发布

i need to change locale settings after successful Authentication.

LocaleResolver:

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

   <bean id="localeResolver"
     class="web.MyLocaleResolver">
   </bean>

   public class MyLocaleResolver extends AbstractLocaleResolver {

   private Locale default = Locale.ENGLISH;

       @Override
       public Locale resolveLocale(HttpServletRequest hsr) {
           return this.default;
       }

       @Override
       public void setLocale(HttpServletRequest hsr, HttpServletResponse hsr1,         Locale default) {
           this.default = default;
       }

   }

Security:

     <form-login login-page="/login" 
          authentication-success-handler- ref="MySuccessAuthHandler"/>
     <beans:bean id="MySuccessAuthHandler" class="web.MySuccessfulAuthenticationHandler">
         <beans:property name="defaultTargetUrl" value="/index.htm"></beans:property>
     </beans:bean>

public class MySuccessfulAuthenticationHandler extends  SavedRequestAwareAuthenticationSuccessHandler  {
  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
        Authentication authentication) throws ServletException, IOException {

        super.onAuthenticationSuccess(request, response, authentication);
        RequestContextUtils.getLocaleResolver(request).setLocale(request, response, Locale.ENGLISH);
   }

}

When i try to set locale by RequestContextUtils i get NullPointer Exception.

3条回答
Anthone
2楼-- · 2019-05-11 13:15

Even though the DispatcherServlet isn't normally reached when using Spring Security, you can add the RequestContextFilter BEFORE your security filter chain which exposes all the request attributes like the localeResolver.

<filter>
    <filter-name>requestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>requestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Even though this should make your example work. For other people: another option is to use WebApplicationContextUtils.getWebApplicationContext(ServletContext) passing it the ServletContext that is available in the HttpServletRequest

查看更多
看我几分像从前
3楼-- · 2019-05-11 13:24

The solution from Kafkaesque is not complete.

But even spring security documentation is wrong:

The LocaleContextHolder needs to be set up to contain the correct Locale before the filters are called. You can either do this in a filter yourself (which must come before the Spring Security filters in web.xml) or you can use Spring's RequestContextFilter.

see https://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html#localization

You can not use RequestContextFilter as this filter is not aware of any LocaleResolver inside your applicationContext. It just uses the Locale from request.getLocale() which is the Accept-Language Header.

If you want to use your own LocaleResolver in this filter you need to write your own:

@Component
public class LocaleRequestContextFilter extends OncePerRequestFilter
{
    // basiert auf RequestContextFilter
    @Inject
    private LocaleResolver      localeResolver;

    @Override
    protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain ) throws ServletException, IOException
    {
        ServletRequestAttributes attributes = new ServletRequestAttributes(request, response);
        initContextHolders(request, attributes);
        try
        {
            filterChain.doFilter(request, response);
        }
        finally
        {
            resetContextHolders();
            attributes.requestCompleted();
        }
    }

    private void initContextHolders ( HttpServletRequest request, ServletRequestAttributes requestAttributes )
    {
        LocaleContextHolder.setLocaleContext(buildLocaleContext(request));
        RequestContextHolder.setRequestAttributes(requestAttributes, false);
    }

    private LocaleContext buildLocaleContext ( final HttpServletRequest request )
    {
        request.setAttribute(DispatcherServlet.LOCALE_RESOLVER_ATTRIBUTE, localeResolver);
        if (this.localeResolver instanceof LocaleContextResolver)
        {
            return ( (LocaleContextResolver) this.localeResolver ).resolveLocaleContext(request);
        }
        else
        {
            return new LocaleContext()
            {
                @Override
                public Locale getLocale ( )
                {
                    return localeResolver.resolveLocale(request);
                }
            };
        }
    }

    private void resetContextHolders ( )
    {
        LocaleContextHolder.resetLocaleContext();
        RequestContextHolder.resetRequestAttributes();
    }
}

and then configure your web.xml

<filter>
    <filter-name>localeRequestContextFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>localeRequestContextFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
查看更多
一纸荒年 Trace。
4楼-- · 2019-05-11 13:30

LocaleResolver is exposed in request context by DispatcherServlet, whereas AuthenticationSuccessHandler is fired before request enters DispatcherServlet (actually, request that fired SavedRequestAwareAuthenticationSuccessHandler never enters DispatcherServlet, because this handler performs a redirect).

Thus, you cannot access LocaleResolver via RequestContextUtils in this case. You can try to inject LocaleResolver into your AuthenticationSuccessHandler explicitly, for example, with autowiring.

查看更多
登录 后发表回答