Programmatically log-in a user using spring security
Asked Answered
I

4

71

The opposite of: How to manually log out a user with spring security?

In my app I have register new user screen, which posts to a controller which creates a new user within db (and does a few obvious checks).I then want this new user to be automatically logged in ... I kind of want somethign like this :

SecurityContextHolder.getContext().setPrincipal(MyNewUser);

Edit Well I have almost implemented based on the answer to How to programmatically log user in with Spring Security 3.1

 Authentication auth = new UsernamePasswordAuthenticationToken(MyNewUser, null);
 SecurityContextHolder.getContext().setPrincipal(MyNewUser);

However, when deployed the jsp can not access my MyNewUser.getWhateverMethods() whereas it does when normal login procedure followed. the code that works nomrally, but throws an error when logged in like above is below :

<sec:authentication property="principal.firstname" /> 
Infest answered 26/10, 2011 at 9:40 Comment(0)
I
51

In my controller i have this, which logs user in as normal :

Authentication auth = 
  new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());

SecurityContextHolder.getContext().setAuthentication(auth);

Where user is my custom user object(implementing UserDetails) that is newly created. The getAuthorities() method does this (just because all my users have the same role):

public Collection<GrantedAuthority> getAuthorities() {
        //make everyone ROLE_USER
        Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
        GrantedAuthority grantedAuthority = new GrantedAuthority() {
            //anonymous inner type
            public String getAuthority() {
                return "ROLE_USER";
            }
        }; 
        grantedAuthorities.add(grantedAuthority);
        return grantedAuthorities;
    }
Infest answered 26/10, 2011 at 14:12 Comment(6)
That is not a login, that is "placing a user object into security context without authenticating it"Gallice
You don't need to authenticate in the question's described scenario. The user just registered. That was the "authentication". It's just that you need to programmatically add the user to the context so Spring knows the user is authenticated.Sanatory
Adding a GrantedAuthority as a third arg to UsernamePasswordAuthenticationToken was what I neededPlutonic
@Gallice I see your point. Would a combination of the accepted answer and Simeon's answer satisfy a real login?Empery
@Empery Simeon's answer is basically the same, just less obvious. It does not call the normal chain of actions, neglecting listeners and possibly creates a weird context. The better but more complicated approach would be to call the AuthenticationManager or ProviderManager in combination with a PreAuth token, e.g. PreAuthenticatedAuthenticationToken to generate an Authentication object before setting it in the context.Gallice
I tried your method but SecurityUtils.getCurrentUserLogin() still prints anonymous@localhost. What might be a reason for that?Keeshakeeshond
P
33

You can also inject your spring security configured UserDetailsManager to your controller and use that to get the UserDetails which holds the principal and authorities to avoid duplicate code:

// inject

@Autowired
private UserDetailsManager manager; 

// use in your method

UserDetails userDetails = manager.loadUserByUsername (token.getUsername ());
Authentication auth = new UsernamePasswordAuthenticationToken (userDetails.getUsername (),userDetails.getPassword (),userDetails.getAuthorities ());
SecurityContextHolder.getContext().setAuthentication(auth);
Pylorus answered 27/2, 2013 at 18:48 Comment(1)
I did not have the UserDatailsManager but the org.springframework.security.core.userdetails.UserDetailsService works too.Richellericher
R
11

From the spring security source AbstractAuthenticationProcessingFilter:

protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
        Authentication authResult) throws IOException, ServletException {

    if (logger.isDebugEnabled()) {
        logger.debug("Authentication success. Updating SecurityContextHolder to contain: " + authResult);
    }

    // you need this
    SecurityContextHolder.getContext().setAuthentication(authResult);

    rememberMeServices.loginSuccess(request, response, authResult);

    if (this.eventPublisher != null) {
        eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
    }

    successHandler.onAuthenticationSuccess(request, response, authResult);
}

Note however that the SecurityContextHolder is usually cleared upon completion of the filter chain.

Remonstrate answered 26/10, 2011 at 13:0 Comment(2)
I don't understand, where is authResult instantiated ?Infest
@Infest You have to instantiate it, as in you have to have your implementation of it and then fill it with data relevant to your user. Have a look at the interface.Remonstrate
O
0

For anyone trying to do this with Reactive Spring Security, this is what I did and it seemed to work.

private Mono<Authentication> authenticateUser(ServerWebExchange exchange, UserDetails userDetails,String rawPassword) 
    {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDetails.getUsername(),rawPassword);
        
        return reactiveAuthenticationManager.authenticate(token).filter(auth -> auth.isAuthenticated()).flatMap(auth ->
        {
            SecurityContextImpl securityContext = new SecurityContextImpl();
            securityContext.setAuthentication(auth);
            return securityContextRepository.save(exchange,securityContext).then(Mono.just(auth));
        });
    }
Oldfangled answered 7/4, 2022 at 1:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.