118 votes

Comment définir manuellement un utilisateur authentifié dans Spring Security / SpringMVC

Après un nouvel utilisateur soumet un "Nouveau compte" forme, je veux connecter manuellement que l'utilisateur en sorte qu'ils n'ont pas de connexion sur la page suivante.

La forme normale de la page de login en passant par le printemps de sécurité de l'intercepteur fonctionne très bien.

Dans le nouveau-compte-forme contrôleur je suis entrain de créer un UsernamePasswordAuthenticationToken et le mettre dans le SecurityContext manuellement:

SecurityContextHolder.getContext().setAuthentication(authentication);

Sur la même page plus tard, j'ai vérifier que l'utilisateur est connecté avec:

SecurityContextHolder.getContext().getAuthentication().getAuthorities();

Ceci renvoie les autorités, j'ai établi plus tôt dans l'authentification. Tout est bien.

Mais quand ce même code est appelé sur la page suivante j'ai la charge, le jeton d'authentification est juste UserAnonymous.

Je ne suis pas clair pourquoi il n'a pas garder l'authentification j'ai mis sur la demande précédente. Toutes les pensées?

  • Pourrait-il avoir à faire avec l'ID de session n'est pas réglée correctement?
  • Est-il quelque chose qui est peut-être écraser mon authentification en quelque sorte?
  • Peut-être que j'ai juste besoin d'une autre étape pour économiser de l'authentification?
  • Ou est-il quelque chose que je dois faire pour déclarer l'authentification à travers l'ensemble de la session, plutôt qu'une seule demande en quelque sorte?

Juste à la recherche de quelques idées qui pourrait m'aider à voir ce qui se passe ici.

71voto

Stuart McIntyre Points 351

Je ne pouvais pas trouver d'autres solutions complètes alors j'ai pensé poster le mien. Cela peut être un peu un bidouillage, mais cela a résolu le problème ci-dessus:

 public void login(HttpServletRequest request, String userName, String password)
{

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, password);

    // Authenticate the user
    Authentication authentication = authenticationManager.authenticate(authRequest);
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(authentication);

    // Create a new session and add the security context.
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
}
 

64voto

Kevin Stembridge Points 3613

J'ai eu le même problème que vous il y a quelque temps. Je ne me souviens pas des détails, mais le code suivant a fonctionné pour moi. Ce code est utilisé dans un flux Spring Webflow, d'où les classes RequestContext et ExternalContext. Mais la partie la plus pertinente pour vous est la méthode doAutoLogin.

 public String registerUser(UserRegistrationFormBean userRegistrationFormBean,
                           RequestContext requestContext,
                           ExternalContext externalContext) {

    try {
        Locale userLocale = requestContext.getExternalContext().getLocale();
        this.userService.createNewUser(userRegistrationFormBean, userLocale, Constants.SYSTEM_USER_ID);
        String emailAddress = userRegistrationFormBean.getChooseEmailAddressFormBean().getEmailAddress();
        String password = userRegistrationFormBean.getChoosePasswordFormBean().getPassword();
        doAutoLogin(emailAddress, password, (HttpServletRequest) externalContext.getNativeRequest());
        return "success";

    } catch (EmailAddressNotUniqueException e) {
        MessageResolver messageResolvable 
                = new MessageBuilder().error()
                                      .source(UserRegistrationFormBean.PROPERTYNAME_EMAIL_ADDRESS)
                                      .code("userRegistration.emailAddress.not.unique")
                                      .build();
        requestContext.getMessageContext().addMessage(messageResolvable);
        return "error";
    }

}


private void doAutoLogin(String username, String password, HttpServletRequest request) {

    try {
        // Must be called from request filtered by Spring Security, otherwise SecurityContextHolder is not updated
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        token.setDetails(new WebAuthenticationDetails(request));
        Authentication authentication = this.authenticationProvider.authenticate(token);
        logger.debug("Logging in with [{}]", authentication.getPrincipal());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    } catch (Exception e) {
        SecurityContextHolder.getContext().setAuthentication(null);
        logger.error("Failure in autoLogin", e);
    }

}
 

17voto

David Parks Points 4201

Finalement compris la racine du problème.

Quand j'ai créer le contexte de sécurité manuellement sans objet session est créée. Seulement, lors de la demande de terminer le traitement ne fait le Printemps, le mécanisme de Sécurité rends compte que l'objet session est nulle (quand il essaie de stocker le contexte de sécurité de la session après que la demande a été traitée).

À la fin de la demande de Printemps de Sécurité crée un nouvel objet de session et l'ID de session. Cependant ce nouvel ID de session ne s'est jamais rendu dans le navigateur, car il se produit à la fin de la demande, après la réponse au navigateur a été faite. Le nouvel ID de session (et donc le contexte de Sécurité contenant mes manuelle de l'utilisateur connecté) sont perdus lors de la prochaine requête contient de la précédente session ID.

6voto

Stephen C Points 255558

Activez la journalisation du débogage pour obtenir une meilleure image de ce qui se passe.

Vous pouvez savoir si les cookies de session sont configurés en utilisant un débogueur côté navigateur pour examiner les en-têtes renvoyés dans les réponses HTTP. (Il y a aussi d'autres moyens.)

Une possibilité est que SpringSecurity mette en place des cookies de session sécurisés et que votre page suivante demandée comporte une URL "http" au lieu de "https". (Le navigateur n'enverra pas de cookie sécurisé pour une URL "http".)

5voto

AlexK Points 31

La nouvelle fonctionnalité de filtrage dans le Servlet 2.4 fondamentalement atténue la restriction que les filtres ne peut fonctionner que dans la demande de flux avant et après que le traitement de la requête par le serveur d'application. Au lieu de cela, Servlet 2.4 filtres peuvent désormais interagir avec la demande répartiteur à chaque centre d'expédition. Cela signifie que lorsqu'une ressource Web envoie une requête à une autre ressource (par exemple, un servlet transfert de la demande à une page JSP dans la même application), un filtre peut être d'exploitation avant la demande est traitée par l'ciblée des ressources. Cela signifie également que si une ressource Web incluent la sortie ou de la fonction à partir d'autres ressources sur le Web (par exemple, une page JSP, y compris la sortie de plusieurs autres pages JSP), Servlet 2.4 filtres peuvent travailler avant et après chacune des ressources incluses. .

Pour activer cette fonctionnalité, vous devez:

web.xml

 <filter>   
        <filter-name>springSecurityFilterChain</filter-name>   
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
    </filter>  
    <filter-mapping>   
        <filter-name>springSecurityFilterChain</filter-name>   
        <url-pattern>/<strike>*</strike></url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>

RegistrationController

  return "forward:/login?j_username=" + registrationModel.getUserEmail()
                + "&j_password=" + registrationModel.getPassword();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X