Spring Security - Redirection vers l’URL précédente après la connexion

Spring Security - Rediriger vers l'URL précédente après la connexion

1. Vue d'ensemble

Cet article se concentrera surhow to redirect a user back to the originally requested URL – after they log in.

Auparavant, nous avons vuhow to redirect to different pages after login with Spring Security pour différents types d'utilisateurs et couvert différents types deredirections with Spring MVC.

L'article est basé sur le top du tutoriel deSpring Security Login.

2. Pratique courante

Les moyens les plus courants d'implémenter la logique de redirection après la connexion sont les suivants:

  • en utilisant l'en-têteHTTP Referer

  • enregistrer la demande initiale dans la session

  • ajout de l'URL d'origine à l'URL de connexion redirigée

Using the HTTP Referer header est un moyen simple, pour la plupart des navigateurs et des clientsHTTP, définissent automatiquementReferer. Cependant, commeReferer est forgeable et repose sur l'implémentation du client, l'utilisation de l'en-têteHTTP Referer pour implémenter la redirection n'est généralement pas suggérée.

Saving the original request in the session est un moyen sûr et robuste d'implémenter ce type de redirection. Outre l'URL d'origine, nous pouvons stocker les attributs de requête d'origine et toutes les propriétés personnalisées de la session.

And appending original URL to the redirected login URL est généralement vu dans les implémentations SSO. Une fois authentifiés via un service SSO, les utilisateurs seront redirigés vers la page demandée à l'origine, avec l'URL ajoutée. Nous devons nous assurer que l'URL ajoutée est correctement codée.

Une autre implémentation similaire consiste à placer l'URL de la demande d'origine dans un champ caché à l'intérieur du formulaire de connexion. Mais ce n'est pas mieux que d'utiliserHTTP Referer

Dans Spring Security, les deux premières approches sont prises en charge de manière native.

3. AuthenticationSuccessHandler

Dans l'authentification par formulaire, la redirection se produit juste après la connexion, qui est gérée dans une instanceAuthenticationSuccessHandler dansSpring Security.

Trois implémentations par défaut sont fournies:SimpleUrlAuthenticationSuccessHandler,SavedRequestAwareAuthenticationSuccessHandler etForwardAuthenticationSuccessHandler. Nous allons nous concentrer sur les deux premières implémentations.

3.1. SavedRequestAwareAuthenticationSuccessHandler

SavedRequestAwareAuthenticationSuccessHandler utilise la requête enregistrée stockée dans la session. Après une connexion réussie, les utilisateurs seront redirigés vers l'URL enregistrée dans la demande d'origine.

Pour la connexion par formulaire,SavedRequestAwareAuthenticationSuccessHandler est utilisé commeAuthenticationSuccessHandler par défaut.

@Configuration
@EnableWebSecurity
public class RedirectionSecurityConfig extends WebSecurityConfigurerAdapter {

    //...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
          .authorizeRequests()
          .antMatchers("/login*")
          .permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .formLogin();
    }

}

Et l'équivalent XML serait:


    
    
    

Supposons que nous ayons une ressource sécurisée à l'emplacement «/ secured». Pour la première fois que vous accédez à la ressource, nous serons redirigés vers la page de connexion. après avoir rempli les informations d'identification et posté le formulaire de connexion, nous serons redirigés vers l'emplacement de ressource initialement demandé:

@Test
public void givenAccessSecuredResource_whenAuthenticated_thenRedirectedBack()
  throws Exception {

    MockHttpServletRequestBuilder securedResourceAccess = get("/secured");
    MvcResult unauthenticatedResult = mvc
      .perform(securedResourceAccess)
      .andExpect(status().is3xxRedirection())
      .andReturn();

    MockHttpSession session = (MockHttpSession) unauthenticatedResult
      .getRequest()
      .getSession();
    String loginUrl = unauthenticatedResult
      .getResponse()
      .getRedirectedUrl();
    mvc
      .perform(post(loginUrl)
        .param("username", userDetails.getUsername())
        .param("password", userDetails.getPassword())
        .session(session)
        .with(csrf()))
      .andExpect(status().is3xxRedirection())
      .andExpect(redirectedUrlPattern("**/secured"))
      .andReturn();

    mvc
      .perform(securedResourceAccess.session(session))
      .andExpect(status().isOk());
}

3.2. SimpleUrlAuthenticationSuccessHandler

Par rapport auxSavedRequestAwareAuthenticationSuccessHandler,SimpleUrlAuthenticationSuccessHandler nous donne plus d'options sur les décisions de redirection.

Nous pouvons activer la redirection basée sur les référents parsetUserReferer(true):

public class RefererRedirectionAuthenticationSuccessHandler
  extends SimpleUrlAuthenticationSuccessHandler
  implements AuthenticationSuccessHandler {

    public RefererRedirectionAuthenticationSuccessHandler() {
        super();
        setUseReferer(true);
    }

}

Ensuite, utilisez-le commeAuthenticationSuccessHandler dansRedirectionSecurityConfig:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
      .antMatchers("/login*")
      .permitAll()
      .anyRequest()
      .authenticated()
      .and()
      .formLogin()
      .successHandler(new RefererAuthenticationSuccessHandler());
}

Et pour la configuration XML:


    
    
    


3.3. Sous la capuche

Il n'y a pas de magie dans ces fonctionnalités faciles à utiliser dansSpring Security. Lorsqu'une ressource sécurisée est demandée, la demande sera filtrée par une chaîne de filtres divers. Les principaux d'authentification et les autorisations seront vérifiés. Si la session de demande n'est pas encore authentifiée,AuthenticationException sera levé.

LesAuthenticationException seront pris dans lesExceptionTranslationFilter, dans lesquels un processus d'authentification sera lancé, ce qui entraînera une redirection vers la page de connexion.

public class ExceptionTranslationFilter extends GenericFilterBean {

    //...

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws IOException, ServletException {
        //...

        handleSpringSecurityException(request, response, chain, ase);

        //...
    }

    private void handleSpringSecurityException(HttpServletRequest request,
      HttpServletResponse response, FilterChain chain, RuntimeException exception)
      throws IOException, ServletException {

        if (exception instanceof AuthenticationException) {

            sendStartAuthentication(request, response, chain,
              (AuthenticationException) exception);

        }

        //...
    }

    protected void sendStartAuthentication(HttpServletRequest request,
      HttpServletResponse response, FilterChain chain,
      AuthenticationException reason) throws ServletException, IOException {

       SecurityContextHolder.getContext().setAuthentication(null);
       requestCache.saveRequest(request, response);
       authenticationEntryPoint.commence(request, response, reason);
    }

    //...

}

Après la connexion, nous pouvons personnaliser les comportements dans unAuthenticationSuccessHandler, comme indiqué ci-dessus.

4. Conclusion

Dans cet exemple deSpring Security, nous avons discuté des pratiques courantes de redirection après la connexion et expliqué les implémentations à l'aide de Spring Security.

Notez queall the implementations we mentioned are vulnerable to certain attacks if no validation or extra method controls are applied. Les utilisateurs peuvent être redirigés vers un site malveillant par de telles attaques.

LeOWASP a fourni uncheat sheet pour nous aider à gérer les redirections et les transferts non validés. Cela nous aiderait beaucoup si nous devions créer nous-mêmes des implémentations.

Le code d'implémentation complet de cet article se trouveover on Github.