2011-12-16 9 views
10

Desidero modificare le impostazioni locali dopo l'accesso a una locale predefinita memorizzata nell'account utente Spring MVC Application (3.0) con Spring Security (3.0).Modifica locale all'accesso

Uso già lo LocaleChangeInterceptor in modo che un utente (non connesso e con accesso) possa modificare la propria locale (con impostazione predefinita dall'intestazione di accettazione). Ma il cliente vuole davvero che l'account specifico di default.

Quindi la mia domanda è, quale sarebbe il modo migliore per modificare le impostazioni locali dopo il login, o c'è già qualche funzionalità di build in Primavera/Sicurezza?

+1

Dal momento che hai già il meccanismo per modificare le impostazioni internazionali, è possibile creare un custom [ 'AuthenticationSuccessHandler'] (http://static.springsource.org/spring- sicurezza/sito/docs/3.0.x/apidocs/org/springframework/security/web/authentication/AuthenticationSuccessHandler.html) per intercettare l'accesso e modificare le impostazioni locali in base alle preferenze dell'utente. Controlla [qui] (http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity-single.html#nsa-form-login) e [qui] (http: // stackoverflow.com/a/6612634/468508) per maggiori informazioni. – bluefoot

risposta

8

La soluzione migliore che ho trovato è stata gestirla in AuthenticationSuccessHandler.

Il seguente è un codice che ho scritto per la mia startup:

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

E la seguente interfaccia dovrebbe essere offerto dalla classe principale. Questo non è necessario ma lo sto utilizzando poiché ho più oggetti in grado di fornire un locale per la sessione.

public interface LocaleProvider {  
    Locale getLocale();  
} 

frammenti di configurazione:

<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

grazie: quell'idea funzionerà, l'ho modificata un po 'per usare gli eventi (che a differenza di InteractiveAuthenticationSuccessEvent e AuthenticationSuccessEvent contiene l'oggetto Request and Reponse) – Ralph

+0

Ho aggiunto gli snippet di configurazione per completezza, per indicare dove e come 'authenticationSuccessHandler 'può essere impostato. - Se non ti piace, allora cancella la parte dalla risposta - Mi dispiace che ho modificato la tua risposta, ma era un testo molto per un commento. – Ralph

+0

sembra non funzionare più, localeResolver sempre null –

2

Utilizzare SessionLocaleResolver e costruirlo come un bean denominato "localeResolver". Questo LocaleResolver risolverà le impostazioni locali verificando innanzitutto le impostazioni locali predefinite con cui è stato creato il resolver. Se è nullo, controllerà se una locale è stata memorizzata nella sessione e, se è nulla, imposterà le impostazioni locali della sessione in base all'intestazione Accept-Language nella richiesta.

Dopo che un utente ha effettuato l'accesso, è possibile chiamare localeResolver.setLocale per memorizzare una locale per la sessione, è possibile farlo in un filtro servlet (assicurarsi di definirlo nel proprio web.xml DOPO la sicurezza di primavera filtro).

Per accedere al vostro localeResolver (o altri fagioli) dal vostro filtro, fare qualcosa di simile nel metodo init:

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

Poi nel doFilterMethod, si dovrebbe essere in grado di lanciare il ServletRequest a un HttpServletRequest, chiama getRemoteUser, esegui qualsiasi logica di business per definire la locale dell'utente e chiama setLocale su LocaleResolver.

Personalmente, non mi interessa che SessionLocaleResolver utilizzi per prima il locale predefinito (preferisco l'ultimo), tuttavia è molto semplice estenderlo e sostituirlo. Se siete interessati a verificare la sessione, la richiesta, allora il valore di default, utilizzare il seguente:

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

Il problema chiave non è il metodo da chiamare per cambiare il locale. Il problema chiave è attivare un metodo dopo l'accesso (che ha accesso ai dettagli di accesso (per il nome utente) e al Local Resolver per modificare il locale) – Ralph

+0

Ho aggiornato la risposta sopra. – aweigold

+0

Scusa ma questo non affronta il problema. Non attiva il processo dopo il login. Il filtro cambierà il locale dell'utente con ogni richiesta dopo che l'utente ha effettuato l'accesso. Questo non è quello che mi viene chiesto: utilizzo un LocaleChangeInterceptor che significa che l'utente può cambiare il suo accesso indipendentemente da qualsiasi impostazione predefinita, il locale specifico dell'utente è solo un valore predefinito - l'utente deve essere in grado di cambiarlo in un secondo momento tramite l'intercettore. --- Ad ogni modo ho già implementato una soluzione del genere (con Spring Interceptor al posto di ServletFilter) ma è un hack. – Ralph

0

mio workarround corrente funziona in questo modo (ma è ancora un hack, perché non è innescato dal login processo):

Ho un Spring HandlerInterceptor che intercetta ogni richiesta. Controlla sempre se c'è già un flag (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) nella sessione utenti che indica che il locale è già aggiornato. Se non c'è alcun contrassegno, l'intercettore controlla se la richiesta appartiene ad un utente autenticato. Se è un utente autenticato allora aggiorna il locale anche se il localResolver e impostare il flag (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) nella sessione

Questa sessione è necessaria roba bandiera, perché il locale deve essere sostituito solo direttamene dopo il login. Quindi in seguito l'utente può cambiare di nuovo il locale attraverso il normale intercettore locale.

Problemi correlati