2011-12-16 25 views
10

Deseo cambiar la configuración regional después de iniciar sesión en una configuración regional predeterminada almacenada en la cuenta de usuario Spring MVC Application (3.0) con Spring Security (3.0).Cambiar la configuración regional en el inicio de sesión

Ya utilizo el LocaleChangeInterceptor para que un usuario (que no haya iniciado sesión, así como un usuario que haya iniciado sesión) pueda cambiar su configuración regional (con el valor predeterminado desde el encabezado accept). Pero el cliente realmente quiere esa cuenta específica predeterminada.

Así que mi pregunta es, ¿cuál sería la mejor manera de cambiar la configuración regional después de iniciar sesión, o ya existe alguna funcionalidad en Spring/Security?

+1

Puesto que ya tiene el mecanismo para cambiar la configuración regional, puede crear una costumbre [ 'AuthenticationSuccessHandler'] (http://static.springsource.org/spring- security/site/docs/3.0.x/apidocs/org/springframework/security/web/authentication/AuthenticationSuccessHandler.html) para interceptar el inicio de sesión y cambiar la configuración regional según las preferencias del usuario. Marque [aquí] (http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity-single.html#nsa-form-login) y [aquí] (http: // stackoverflow.com/a/6612634/468508) para más información. – bluefoot

Respuesta

8

La mejor solución que pude encontrar fue manejar esto en AuthenticationSuccessHandler.

El siguiente es un código que escribí para mi el inicio:

public class LocaleSettingAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 
    @Resource 
    private LocaleResolver localeResolver; 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
     setLocale(authentication, request, response); 
     super.onAuthenticationSuccess(request, response, authentication); 
    } 

    protected void setLocale(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { 
     if (authentication != null) { 
      Object principal = authentication.getPrincipal(); 
      if (principal instanceof LocaleProvider) { 
       LocaleProvider localeProvider = (LocaleProvider) principal; 
       Locale providedLocale = localeProvider.getLocale(); 
       localeResolver.setLocale(request, response, providedLocale); 
      } 
     } 
    } 
} 

Y la siguiente interfaz debe ser ofrecidas por su principal clase. Esto no es necesario pero lo estoy usando ya que tengo varios objetos capaces de proporcionar una configuración regional para la sesión.

public interface LocaleProvider {  
    Locale getLocale();  
} 

fragmentos de configuración:

<security:http ...> 
    <security:custom-filter ref="usernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER"/> 
</security:http> 

<bean id="usernamePasswordAuthenticationFilter" 
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
    <property name="filterProcessesUrl" value="/login/j_spring_security_check"/> 
    <property name="authenticationManager" ref="authenticationManager"/> 
    <property name="authenticationFailureHandler"> 
     <bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> 
      <property name="defaultFailureUrl" value="/login?login_error=t"/> 
     </bean> 
    </property> 
    <property name="authenticationSuccessHandler"> 
     <bean class="LocaleSettingAuthenticationSuccessHandler"> 
    </property> 
</bean> 
+0

gracias: esa idea funcionará, la modifiqué un poco para usar eventos (que en contraste con InteractiveAuthenticationSuccessSuccessEvent y AuthenticationSuccessEvent contiene el objeto Request and Reponse) – Ralph

+0

He agregado los fragmentos de configuración para la integridad, para indicar dónde y cómo 'authenticationSuccessHandler 'se puede configurar. - Si no te gusta, borra la parte de la respuesta. Lamento haber editado tu respuesta, pero fue para recibir mucho comentario. – Ralph

+0

parece que ya no funciona, localeResolver siempre nulo –

2

Utilice SessionLocaleResolver y contrólelo como un bean llamado "localeResolver". Este LocaleResolver resolverá las configuraciones regionales al verificar primero la configuración regional predeterminada con la que se construyó el sistema de resolución. Si es nulo, comprobará si se ha almacenado una configuración regional en la sesión y, si es nula, configurará la configuración regional de la sesión según el encabezado Aceptar idioma de la solicitud.

Después de que un usuario haya iniciado sesión, puede llamar a localeResolver.setLocale para almacenar una configuración regional en la sesión, puede hacerlo en un filtro de servlet (asegúrese de definirlo en su web.xml DESPUÉS de su seguridad de primavera filtrar).

Para obtener acceso a su localeResolver (u otros granos) de su filtro, hacer algo como esto en el método init:

@Override 
public void init(FilterConfig fc) throws ServletException { 
    ServletContext servletContext = fc.getServletContext(); 
    ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext); 
    this.localeResolver = context.getBean(SessionLocaleResolver.class); 
} 

Luego, en el doFilterMethod, usted debe ser capaz de emitir el ServletRequest a una HttpServletRequest, llame a getRemoteUser, realice cualquier lógica comercial para definir la configuración regional de ese usuario y llame a setLocale en LocaleResolver.

Personalmente, no me importa que el SessionLocaleResolver use primero el local predeterminado (prefiero el último), sin embargo, es muy fácil de ampliar y anular. Si usted está interesado en el control de la sesión, entonces la petición, el valor por defecto, utilice la siguiente:

import org.springframework.stereotype.Component; 
import org.springframework.web.util.WebUtils; 

import javax.servlet.http.HttpServletRequest; 
import java.util.Locale; 

// The Spring SessionLocaleResolver loads the default locale prior 
// to the requests locale, we want the reverse. 
@Component("localeResolver") 
public class SessionLocaleResolver extends org.springframework.web.servlet.i18n.SessionLocaleResolver{ 

    public SessionLocaleResolver(){ 
     //TODO: make this configurable 
     this.setDefaultLocale(new Locale("en", "US")); 
    } 

    @Override 
    public Locale resolveLocale(HttpServletRequest request) { 
     Locale locale = (Locale) WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME); 
     if (locale == null) { 
      locale = determineDefaultLocale(request); 
     } 
     return locale; 
    } 

    @Override 
    protected Locale determineDefaultLocale(HttpServletRequest request) { 
     Locale defaultLocale = request.getLocale(); 
     if (defaultLocale == null) { 
      defaultLocale = getDefaultLocale(); 
     } 
     return defaultLocale; 
    } 

} 
+0

El problema clave no es qué método debe llamarse para cambiar el local. El problema clave es activar algún método después de iniciar sesión (que tiene acceso a los detalles de inicio de sesión (para el nombre de usuario) y al Local Resolver para cambiar el local) – Ralph

+0

Actualicé la respuesta anterior. – aweigold

+0

Lo siento, pero esto no soluciona el problema. No activa el proceso después de iniciar sesión. El filtro cambiará el local del usuario con cada solicitud después de que el usuario haya iniciado sesión. Eso no es lo que me piden: uso un LocaleChangeInterceptor, esto significa que el usuario puede cambiar su inicio de sesión independientemente de cualquier valor predeterminado, el usuario específico local es solo un valor predeterminado: el usuario debe poder cambiarlo más adelante a través de ese interceptor. --- De todos modos, ya he implementado una solución como esa (con un Spring Interceptor en lugar de ServletFilter) pero es un hack. – Ralph

0

Mi workarround actual funciona de esta manera (pero se sigue siendo un truco, ya que no es provocada por el inicio de sesión proceso):

Tengo un Spring Handler Interceptor que intercepta todas las solicitudes. Comprueba siempre si ya existe un indicador (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) en la sesión de usuarios que indica que el local ya está actualizado. Si no existe dicho indicador, el interceptor verifica si la solicitud pertenece a un usuario autenticado. si es un usuario autenticado entonces se actualiza el local, aunque el localResolver y establece el indicador (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) en la sesión

Esta sesión se necesita mercancía de la bandera, porque el local, sólo debe cambiarse después de direclty de inicio de sesión. Luego, el usuario puede cambiar el local nuevamente a través del interceptor de cambio local normal.

public class LocalChangeUserInterceptor extends HandlerInterceptorAdapter { 

    /** Session key, used to mark if the local is set. */ 
    private static final String LOCALE_ALREADY_SET_SESSION_ATTRIBUTE = "LocalChangeUserInterceptor.localeAlreadySet"; 

    /** The locale resolver. */ 
    @Resource 
    private LocaleResolver localeResolver; 

    @Resource 
    private UserService userService; 

    @Override 
    public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) 
      throws Exception { 
     if (!isLocaleAlreadySet(request)) { 
      User currentAuthenticatedUser = getCurrentUserOrNull(); 
      if (currentAuthenticatedUser != null) { 
       this.localeResolver.setLocale(request, response, currentAuthenticatedUser.getLocale()); 
       request.getSession().setAttribute(LOCALE_ALREADY_SET_SESSION_ATTRIBUTE, "true"); 
      } 
     } 
     return true; 
    } 

    /** 
    * Check if there is an session attribute that states that the local is already set once. 
    * @param request the request 
    * @return true, if is locale already set 
    */ 
    private boolean isLocaleAlreadySet(final HttpServletRequest request) { 
     HttpSession sessionOrNull = request.getSession(false); 
     return ((sessionOrNull != null) && (sessionOrNull.getAttribute(LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) != null)); 
    } 

    /** 
    * Get the current user or null if there is no current user. 
    * @return the current user 
    */ 
    public User getCurrentUserOrNull() { 
     Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
     if ((authentication == null) || (authentication instanceof AnonymousAuthenticationToken)) { 
      return null; 
     } else { 
      return this.userService.getUser(authentication); 
     } 
    } 
} 
Cuestiones relacionadas