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" /> 

4 Answers 4

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;
    }
Sign up to request clarification or add additional context in comments.

6 Comments

That is not a login, that is "placing a user object into security context without authenticating it"
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.
Adding a GrantedAuthority as a third arg to UsernamePasswordAuthenticationToken was what I needed
@dube I see your point. Would a combination of the accepted answer and Simeon's answer satisfy a real login?
@LukeSolar 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.
|
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);

1 Comment

I did not have the UserDatailsManager but the org.springframework.security.core.userdetails.UserDetailsService works too.
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.

2 Comments

I don't understand, where is authResult instantiated ?
@NimChimpsky 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.
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));
        });
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.