【问题标题】:Spring security + LocaleResolverSpring 安全性 + LocaleResolver
【发布时间】:2017-09-13 23:29:43
【问题描述】:

身份验证成功后,我需要更改区域设置。

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;
       }

   }

安全性:

     <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);
   }

}

当我尝试通过RequestContextUtils 设置语言环境时,我得到 NullPointer 异常。

【问题讨论】:

  • 然后查看堆栈跟踪的第一行:它会准确地告诉您异常发生在哪个文件的哪一行。您的代码很奇怪:您似乎关心 i18n,尽管您支持每个用户的唯一区域设置:英语。

标签: java spring-mvc spring-security locale


【解决方案1】:

LocaleResolverDispatcherServlet 暴露在请求上下文中,而AuthenticationSuccessHandler 在请求进入DispatcherServlet 之前被触发(实际上,触发SavedRequestAwareAuthenticationSuccessHandler 的请求永远不会进入DispatcherServlet,因为这个处理程序执行重定向) .

因此,在这种情况下,您无法通过RequestContextUtils 访问LocaleResolver。您可以尝试将LocaleResolver 显式注入到您的AuthenticationSuccessHandler 中,例如使用自动装配。

【讨论】:

  • 我一直在尝试这样做(自动装配),但我一直得到一个空值,有什么想法吗?
  • 对我来说是一样的,总是为空。我试过这个:forum.spring.io/forum/spring-projects/security/… 并且总是为空。可以举个例子吗?
【解决方案2】:

Kafkaesque 的解决方案并不完整。

但即使是 spring 安全文档也是错误的:

需要设置 LocaleContextHolder 以包含正确的 调用过滤器之前的语言环境。您可以在 过滤自己(必须在 Spring Security 过滤器之前 web.xml) 或者你可以使用 Spring 的 RequestContextFilter。

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

您不能使用RequestContextFilter,因为此过滤器不知道您的应用程序上下文中的任何LocaleResolver。它只是使用来自request.getLocale() 的区域设置,即Accept-Language Header。

如果您想在此过滤器中使用自己的 LocaleResolver,您需要编写自己的:

@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();
    }
}

然后配置你的 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>

【讨论】:

  • 已尝试但 RequestContextUtils.getLocaleResolver(request) 继续为空。
  • @Robert:你调用了错误的方法。 RequestContextUtils.getLocaleResolver(request) 的 Javadoc 说“返回已由 DispatcherServlet 绑定到请求的 LocaleResolver。”。在过滤器内部,DispatcherServlet 尚未运行。而且您不需要 localeResolver,您需要语言环境或 LocaleContext。也许你应该参考这里提出的解决方案提出一个新问题。
【解决方案3】:

即使在使用 Spring Security 时通常无法访问 DispatcherServlet,您也可以在安全过滤器链之前添加 RequestContextFilter,它会公开所有请求属性,例如 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>

即使这应该使您的示例工作。对于其他人:另一种选择是使用 WebApplicationContextUtils.getWebApplicationContext(ServletContext) 将 HttpServletRequest 中可用的 ServletContext 传递给它

【讨论】:

    猜你喜欢
    • 2012-08-19
    • 2012-05-05
    • 2018-01-17
    • 2014-09-11
    • 2020-07-01
    • 2017-12-21
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多