【问题标题】:Spring security + i18n = how to make it work together?Spring security + i18n = 如何使其协同工作?
【发布时间】:2012-01-18 16:24:05
【问题描述】:

我在这里的第一个问题,我会尽量具体。我对 Spring 很陌生,我正在尝试创建非常简单的预订系统(但这实际上并不重要)。重要的是我正在创建一些基本模板,然后我将用真实的网页填写这些模板。应用程序适用于休眠、mysql,我还设置了 i18n 和 spring security。问题是我无法更改我的语言环境。唯一有效的方法是更改​​默认值。 首先,我浏览了很多 Web,我发现将 i18n 与 spring security 一起使用比通常更复杂。我发现我需要额外的过滤器:

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

我发现这个过滤器确实在安全过滤器之前处理,但是它不会以以下形式解析请求:http://someserver.com/bla/home?locale=en。我调试了它,似乎它不是为此目的而创建的(这就是我需要的)。 这取自 spring 示例“联系人”,但是在此示例中,我找不到任何实际针对更改语言的代码。效果是它根本不起作用。它总是试图将语言环境更改为我的默认语言环境。好消息是,如果在调试模式下我手动将语言环境设置更改为其他设置,它工作正常,所以我心中充满希望...... ;-)

然后我找到了其他方法 - 通过创建我们自己的过滤器。我所做的是将找到的示例(不要记住作者)与 RequestContextFilter 的创建方式合并在一起。毕竟RequestContextFilter 工作正常 - 刚刚完成解析我的请求。这是新过滤器的代码:

public class InternationalizationFilter extends OncePerRequestFilter {

@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 {
    final String newLocale = request.getParameter("locale");
    if (newLocale != null) {
        final Locale locale = StringUtils.parseLocaleString(newLocale
                .toLowerCase());
        LocaleContextHolder.setLocale(locale);
    }
    try {
        filterChain.doFilter(request, response);
    } finally {

        LocaleContextHolder.resetLocaleContext();
    }
}

}

如您所见,请求参数语言环境已解析并已设置语言环境。有2个问题: 1. 发送请求xxxxx?locale=en 后,它创建没有“国家”属性的区域设置(仅设置语言)。老实说,我不知道这是否有任何问题——也许不是。 2. 更严重的问题是它不起作用......我的意思是它在过滤器链中的正确位置(在安全链之前),它产生正确的语言环境并以与RequestContextFilter 完全相同的方式设置它...但它根本不起作用。

如果有人可以根据我给出的示例或任何其他示例让我知道如何使 i18n 与 spring-security 一起使用,我将非常高兴...

谢谢!

附加信息: 我做了一些实验,似乎请求中的 Locale 实例在某种程度上是特定的。

看这段代码(修改了RequestContextFilter类):

    @Override
protected void doFilterInternal(final HttpServletRequest request,
        final HttpServletResponse response, final FilterChain filterChain)
        throws ServletException, IOException {

    final ServletRequestAttributes attributes = new ServletRequestAttributes(
            request);
    final Locale l = Locale.GERMAN;
    final Locale l2 = request.getLocale();
    LocaleContextHolder.setLocale(l,
            this.threadContextInheritable);
    RequestContextHolder.setRequestAttributes(attributes,
            this.threadContextInheritable);
    if (logger.isDebugEnabled()) {
        logger.debug("Bound request context to thread: " + request);
    }
(...)

如果使用此方法:LocaleContextHolder.setLocale(l, this.threadContextInheritable); 我通过 locale 'l' 它根本不起作用。我的意思是即使你明确地改变了语言环境也不会改变。 另一方面,如果我通过那里将 Locale 'l2' 修改为德语(在调试模式下)它工作正常!

这意味着由于某种原因来自 request.getLocale() 的 Locale 实例在某种程度上受到了青睐,也许稍后在代码中发生了一些我不知道/不理解的事情......

请让我知道我应该如何将这个 i18n 与安全性一起使用,因为我已经到了必须承认我不知道发生了什么的地步......

-====-======-======--=======-====

最终解决方案/答案(但仍然没有什么疑问) 感谢拉尔夫,我设法解决了我的问题。以前我走错了方向,但 roo 生成的项目推动了我前进。 看来我一直以错误/不准确的方式添加拦截器(以前的代码):

<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
<bean id="localeResolver"
    class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <property name="defaultLocale" value="pl"/>
</bean>
<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
    <property name="interceptors">
        <ref bean="localeChangeInterceptor" />
    </property>
</bean>

这种方式拦截器由于某种原因从未被调用。

将拦截器def更改为:

<mvc:interceptors>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
</mvc:interceptors>

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

<bean id="handlerMapping"
    class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>

...它开始正常工作,无需对 security/web.xml 进行任何其他更改。

现在问题消失了,但我不确定发生了什么。根据我在第二个示例(有效的示例)中的理解,我将拦截器设为“全局”。但是为什么第一个示例中定义的拦截器不起作用?有什么提示吗?

再次感谢您的帮助! N.

【问题讨论】:

  • 嗨..我试过你的拦截器配置,但它不起作用。我的语言环境在登录页面上没有改变。但是成功登录后它工作正常。在登录页面上,它仅适用于系统区域设置。

标签: spring spring-mvc localization internationalization spring-security


【解决方案1】:
  1. 在发送请求 xxxxx?locale=en 后,它会创建没有“国家”属性的区域设置(仅设置语言)。

这是预期的行为。在java中有某种层次结构。 语言比国家更通用。

背后的想法是,您可以在特定国家/地区的文件中使用更常用语言的文本,但也可以使用一些单位(如货币)。

@见:http://java.sun.com/developer/technicalArticles/Intl/IntlIntro/


  1. 更严重的问题是它不起作用...

它应该可以在没有任何手工实现的情况下工作!

需要注册Local Change Interceptor,登录页面需要设置permitAll。

<mvc:interceptors>         
     <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" p:paramName="lang"/>
</mvc:interceptors>

<http auto-config="true" use-expressions="true">
    <form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t"/>
    <logout logout-url="/resources/j_spring_security_logout"/>

    <!-- Configure these elements to secure URIs in your application -->
    <intercept-url pattern="/login" access="permitAll" />
    <intercept-url pattern="/resources/**" access="permitAll" />
    <intercept-url pattern="/**" access="isAuthenticated()" />
</http>

要查看此示例运行,请使用该 roo 脚本创建一个 roo 项目:

// Spring Roo 1.1.5.RELEASE [rev d3a68c3] log opened at 2011-12-13 09:32:23
project --topLevelPackage de.humanfork.test --projectName localtest --java 6
persistence setup --database H2_IN_MEMORY --provider HIBERNATE 
ent --class ~.domain.Stuff
field string --fieldName title
controller all --package ~.web
security setup
web mvc language --code de
web mvc language --code es

那么您必须只更改安全过滤器 intersept-url 模式,如我上面显示的 (applicationContext-security.xml)!

现在您有一个应用程序,用户可以通过应用程序中的本地更改拦截器更改其本地(当用户登录时)以及当他未登录时(在登录页面中)

【讨论】:

  • 好的,感谢您的快速回答 - 这就是我的预期。如果出现主要问题(区域设置更改),也许您也可以让我走上正确的道路。再次感谢!
  • @Nirwan:查看我的扩展答案 - 它并没有真正解释为什么它不适合您,但它会引导您了解本地更改拦截器运行良好的示例。
  • 感谢拉尔夫。通过 roo 示例,我终于设法让它运行起来。就像您说的不需要手动实施...请查看我的问题以了解详细信息出了什么问题-也许您可以告诉我我实际上做了什么,因为我不确定;)无论如何,再次感谢! !
  • 这个实现的问题在于它只是 Spring MVC 特定的。当您需要在自定义 Spring Security 身份验证处理程序中获取区域设置时,您将没有正确的一组。 localeChangeInterceptor 是 Spring MVC 特定的。 :(
  • @and-dev - 我有同样的问题,几年后,但你是如何解决这个问题的?
【解决方案2】:

我在使用 GWT app 时遇到了类似的本地化问题。我注意到的问题是,当我们映射时

<filter-mapping>
 <filter-name>localizationFilter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>

到过滤器,甚至图像请求都被路由到过滤器。这些请求有时会忽略 locale 参数,因此当多个请求命中过滤器时,Locale 参数不会。因此,我一收到 locale 参数,就将其放入会话中。记录所有请求标头和值,您可能会找到根本原因。

【讨论】:

    猜你喜欢
    • 2011-08-19
    • 2023-02-01
    • 2015-03-18
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    • 1970-01-01
    • 2013-02-15
    • 2017-08-12
    相关资源
    最近更新 更多