web-dev-qa-db-fra.com

Connexion automatique après une inscription réussie

hé tous je veux faire une connexion automatique après une inscription réussie au printemps ce qui signifie: j'ai une page protégée qui nécessite une connexion pour y accéder et je veux après l'inscription, ignorer la page de connexion et procéder à une connexion automatique afin que l'utilisateur puisse voir cette page protégée, si? J'utilise Spring 3.0, Spring Security 3.0.2 comment procéder. 

29
Mahmoud Saleh

Cela peut être fait avec la sécurité du ressort de la manière suivante (semi-pseudo-code):

import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

@Controller
public class SignupController
{

    @Autowired
    RequestCache requestCache;

    @Autowired
    protected AuthenticationManager authenticationManager;

    @RequestMapping(value = "/account/signup/", method = RequestMethod.POST)
    public String createNewUser(@ModelAttribute("user") User user, BindingResult result,  HttpServletRequest request, HttpServletResponse response) {
        //After successfully Creating user
        authenticateUserAndSetSession(user, request);

        return "redirect:/home/";
    }

    private void authenticateUserAndSetSession(User user, HttpServletRequest request) {
        String username = user.getUsername();
        String password = user.getPassword();
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);

        // generate session if one doesn't exist
        request.getSession();

        token.setDetails(new WebAuthenticationDetails(request));
        Authentication authenticatedUser = authenticationManager.authenticate(token);

        SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
    }
}

Mise à jour: pour contenir uniquement comment créer la session après l'enregistrement

40
Spring Monkey

Dans Servlet 3+, vous pouvez simplement faire request.login("username","password") et, en cas de succès, rediriger vers la page de votre choix. Vous pouvez faire la même chose pour la déconnexion automatique.

Voici le lien vers la section de la documentation qui en parle: http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#servletapi-3

12
Henok T

Juste un commentaire à la première réponse sur la façon d’autowire authenticationManager.

Vous devez définir un alias lorsque vous déclarez authentication-manager dans votre fichier demandeurion-servlet.xml ou applicationContext-security.xml:

<authentication-manager alias="authenticationManager>
    <authentication-provider>
        <user-service>
            <user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN" />
            <user name="bob" password="bobspassword" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>
</authentication-manager>

De plus, lors de votre authentification, une exception AuthenticationException peut être lancée. Vous devez donc l'attraper:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword());
request.getSession();

token.setDetails(new WebAuthenticationDetails(request));

try{
    Authentication auth = authenticationManager.authenticate(token);

    SecurityContextHolder.getContext().setAuthentication(auth);
} catch(Exception e){
        e.printStackTrace();
}

return "redirect:xxxx.htm";
8
user844085
  1. Configurez le fichier web.xml pour permettre à Spring Security de gérer les transferts pour une URL de traitement de la connexion.
  2. Traiter la demande d'inscription, par exemple créer un utilisateur, mettre à jour la liste de contrôle d'accès, etc.
  3. Transférez-le avec le nom d'utilisateur et le mot de passe pour vous connecter à l'URL de traitement pour l'authentification.
  4. Bénéficiez des avantages de toute la chaîne de filtres Spring Security, par ex. protection de fixation de session.

Comme les transferts sont internes, il apparaîtra à l'utilisateur qu'ils sont enregistrés et connectés au cours de la même demande.

Si votre formulaire d'inscription ne contient pas les noms de paramètre nom d'utilisateur et mot de passe corrects, transmettez une version modifiée de la demande (à l'aide de HttpServletRequestWrapper) au noeud final de connexion Spring Security.

Pour que cela fonctionne, vous devez modifier votre fichier web.xml afin que le descripteur de chaîne de sécurité Spring Security transmette le login-processing-url. Par exemple:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<!-- Handle authentication for normal requests. -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Handle authentication via forwarding for internal/automatic authentication. -->
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/login/auth</url-pattern>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Source: blog mohchi

2
andy

L'utilisation de SecurityContextHolder.getContext (). SetAuthentication (Authentication) permet d'exécuter le travail, mais contournera la chaîne de filtres de sécurité Spring, ce qui créera un risque pour la sécurité.

Par exemple Disons que dans mon cas, lorsque l'utilisateur réinitialise le mot de passe, je voulais qu'il se connecte au tableau de bord sans se connecter à nouveau. Lorsque j'ai utilisé l'approche susmentionnée, il me faut un tableau de bord, mais cela a contourné le filtre de concurrence que j'ai appliqué afin d'éviter les connexions simultanées. Voici le morceau de code qui fait le travail:

UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(empId, password);
Authentication auth = authenticationManager.authenticate(authToken);
SecurityContextHolder.getContext().setAuthentication(auth);

Utiliser l'attribut login-processing-url avec un simple changement dans web.xml

security-xml

<form-login login-page="/login" 
            always-use-default-target="false" 
            default-target-url="/target-url" 
            authentication-failure-url="/login?error"
            login-processing-url="/submitLogin"/>

web.xml

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/submitLogin</url-pattern>
    <dispatcher>FORWARD</dispatcher>
 </filter-mapping>

En ajoutant ce morceau de code dans web.xml, vous transférez votre demande de transfert explicite que vous ferez lors de la connexion automatique et que vous transmettez à la chaîne de filtres de sécurité à ressort.

J'espère que ça aide 

1
Ankit Pandoh

J'ai incorporé le même scénario, ci-dessous l'extrait de code. Pour obtenir l'instance de AuthenticationManager, vous devez redéfinir la méthode authenticationManagerBean () de la classe WebSecurityConfigurerAdapter.

SecurityConfiguration (étend WebSecurityConfigurerAdapter)

@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

Manette

    @Autowired
    protected AuthenticationManager authenticationManager;

    @PostMapping("/register")
    public ModelAndView registerNewUser(@Valid User user,BindingResult bindingResult,HttpServletRequest request,HttpServletResponse response) {
        ModelAndView modelAndView = new ModelAndView();
        User userObj = userService.findUserByEmail(user.getEmail());
        if(userObj != null){
            bindingResult.rejectValue("email", "error.user", "This email id is already registered.");
        }
        if(bindingResult.hasErrors()){
            modelAndView.setViewName("register");
            return modelAndView;
        }else{
            String unEncodedPwd = user.getPassword();
            userService.saveUser(user);
            modelAndView.setViewName("view_name");
            authWithAuthManager(request,user.getEmail(),unEncodedPwd);
        }   
        return modelAndView;
    }


    public void authWithAuthManager(HttpServletRequest request, String email, String password) {
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(email, password);
        authToken.setDetails(new WebAuthenticationDetails(request));
        Authentication authentication = authenticationManager.authenticate(authToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }
1
Rahul Gupta

Ceci est la réponse à la question ci-dessus In Controller:

@RequestMapping(value = "/registerHere", method = RequestMethod.POST)
    public ModelAndView registerUser(@ModelAttribute("user") Users user, BindingResult result,
            HttpServletRequest request, HttpServletResponse response) {
        System.out.println("register 3");

        ModelAndView mv = new ModelAndView("/home");
        mv.addObject("homePagee", "true");

        String uname = user.getUsername();

        if (userDAO.getUserByName(uname) == null) {

            String passwordFromForm = user.getPassword();
            userDAO.saveOrUpdate(user);

            try {
                authenticateUserAndSetSession(user, passwordFromForm, request);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


        }

        System.out.println("register 4");

        log.debug("Ending of the method registerUser");
        return mv;
    }

La méthode ci-dessus dans le contrôleur est définie comme suit:

`private void authenticateUserAndSetSession(Users user, String passwor`dFromForm, HttpServletRequest request){

        String username = user.getUsername();
        System.out.println("username:  " + username + " password: " + passwordFromForm);                        

        UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, passwordFromForm, userDetails.getAuthorities());
        request.getSession();

        System.out.println("Line Authentication 1");

        usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetails(request));

        System.out.println("Line Authentication 2");

        Authentication authenticatedUser = authenticationManager.authenticate(usernamePasswordAuthenticationToken);

        System.out.println("Line Authentication 3");


        if (usernamePasswordAuthenticationToken.isAuthenticated()) {
            SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
            System.out.println("Line Authentication 4");

        }

     request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());// creates context for that session.

        System.out.println("Line Authentication 5");

        session.setAttribute("username", user.getUsername());

        System.out.println("Line Authentication 6");

        session.setAttribute("authorities", usernamePasswordAuthenticationToken.getAuthorities());

        System.out.println("username:  " + user.getUsername() + "password: " + user.getPassword()+"authorities: "+ usernamePasswordAuthenticationToken.getAuthorities());

        user = userDAO.validate(user.getUsername(), user.getPassword());
        log.debug("You are successfully register");

    }

D'autres réponses n'ont pas suggéré de le mettre dans try/catch pour ne pas comprendre pourquoi la logique ne fonctionne pas lorsque le code est exécuté ... et qu'il n'y a rien d'erreur ni d'exception sur la console. Donc, si vous ne le mettez pas en essai, vous ne recevrez pas d'exception pour les mauvais identifiants. 

0
Yogesh Devgun

C'est une alternative à l'intégration Servlet 3+. Si vous utilisez la connexion de formulaire de Spring Security, vous pouvez simplement déléguer des tâches à votre page de connexion. Par exemple:

@PostMapping("/signup")
public String signUp(User user) {
    // encode the password and save the user
    return "forward:/login";
}

En supposant que vous ayez les champs username et password dans votre formulaire, le «transfert» enverra ces paramètres et Spring Security utilisera ceux-ci pour s'authentifier.

L'avantage que j'ai trouvé avec cette approche est que vous ne dupliquez pas votre formLogin's defaultSuccessUrl (exemple de configuration de sécurité ci-dessous). Il nettoie également votre contrôleur en ne nécessitant pas de paramètre HttpServletRequest.

@Override
public void configure(HttpSecurity http) {
    http.authorizeRequests()
            .antMatchers("/", "/signup").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginPage("/login")
            .defaultSuccessUrl("/home", true)
            .permitAll();
}
0

La réponse de Spring Monkey fonctionne très bien mais j'ai rencontré un problème délicat lors de sa mise en œuvre.

Mon problème était dû au fait que je réglais la page d’enregistrement sur "aucune sécurité", par exemple:

<http pattern="/register/**" security="none"/>

Je pense que cela ne provoque pas l'initialisation de SecurityContext et que, par conséquent, après que l'utilisateur se soit inscrit, l'authentification sur le serveur ne peut pas être enregistrée.

Je devais changer le contournement de la page de registre en le définissant dans IS_AUTHENTICATED_ANONYMOUSLY

<http authentication-manager-ref="authMgr">
  <intercept-url pattern="/register/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
  ...
</http>
0
gerrytan