在 Spring Security 登录期间设置 Grails/Spring Locale - 如何?

Posted

技术标签:

【中文标题】在 Spring Security 登录期间设置 Grails/Spring Locale - 如何?【英文标题】:Setting Grails/Spring Locale during Spring Security login - how? 【发布时间】:2011-12-16 10:44:55 【问题描述】:

在我的 Grails 1.3.7 应用程序中,我将用户的语言和国家/地区存储在域类中。

在(Spring Security)登录期间,我想将用户会话的语言环境设置为为此用户存储的语言/国家/地区。

我正在实现我的自定义监听器,在 grails-app/spring/resources.groovy 中注册:

class MyListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> 
    def config = org.codehaus.groovy.grails.commons.ConfigurationHolder.config

    void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) 
            User user = User.findByUsername(event.authentication.name)
            Locale locale = new Locale(user.getLanguage(), user.getCountry())

            LocaleContextHolder.setLocale(locale)
            HttpServletRequest request = SecurityRequestHolder.request
            HttpServletResponse response = SecurityRequestHolder.response
            LocaleResolver locRes = RequestContextUtils.getLocaleResolver(request)

            locRes.setLocale(request, response, locale)
    

我的问题是 RequestContextUtils.getLocaleResolver 返回 null。

如何设置新的语言环境?

【问题讨论】:

【参考方案1】:

我遇到了同样的问题并提出了解决方法。 LocaleResolver 默认为SessionLocaleResolver。显然,从名称来看,它通过键SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME 将语言环境存储在会话中。 因此,您可以在用户登录后手动设置。 这是我来自Config.groovy的代码

grails.plugin.springsecurity.useSecurityEventListener = true
grails.plugin.springsecurity.onInteractiveAuthenticationSuccessEvent =  InteractiveAuthenticationSuccessEvent event, appCtx ->
    User.withNewSession 
        User user = User.get(event.authentication.principal.id)
        if (user?.locale) 
            HttpServletRequest request = SecurityRequestHolder.request
            // SmartConfigLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME if you use locale-configuration plugin
            WebUtils.setSessionAttribute(request, SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, user.locale)
        
    

这是最简单的方法。如您所见,我使用了callback closure,而不是在resources.groovy 中声明单独的类和注册bean。 此外,最糟糕的是,您可以保存 Locale 字段,而不是保存语言和国家/地区的两个单独字段。

还有这一行

User user = User.findByUsername(event.authentication.name)

你可以改写更高效

User user = User.get(event.authentication.principal.id)

它将通过 id 使用 Hibernate 二级缓存,并且对于区分大小写的用户名是安全的。

【讨论】:

【参考方案2】:

您应该创建一个LocaleResolver 实现,而不是在登录步骤中执行此操作,该实现可以确定正确的Locale 以用于给定的HttpServletRequest

您的应用需要知道如何为用户发出的每个后续请求解析区域设置。在 LocaleResolver 或 LocaleContextHolder 中手动设置 Locale 只会影响为 current 请求存储 Locale 的 ThreadLocal。新请求将不会具有相同的 ThreadLocal,并且会看到未设置的 Locale。

创建一个从 Spring Security 上下文中获取当前登录的UserDetails 并找到用户的语言环境的实现应该是微不足道的(或者您可以将详细信息存储在 Session 等中,选择是由你决定)。

【讨论】:

谢谢马特。我无法真正验证在 LocaleResolver 和 LocaleContextHolder 中设置 Locale 是否只会影响当前请求 - 出于好奇,我将其放入“changeLanguage”Grails 控制器操作中,更改后,更新的 Locale 将保留以下请求也是如此。也许 Grails 在那里有什么魔力?

以上是关于在 Spring Security 登录期间设置 Grails/Spring Locale - 如何?的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring Security 中使用 Oauth2 手动进行身份验证不会在整个会话期间保持 SecurityContext

在 Spring Security 3.0 中登录时设置 cookie

Spring Security 在登录响应中使用新的会话令牌设置 CSRF

如何通过 REST API 为 Spring-social 和 spring-security 设置登录服务?

Spring Security 设置登录的用户名和密码的三种方式

通过facebook登录后设置spring security记住我的cookie