在 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 设置登录服务?