Spring Security custom UserDetailsService and custom User class

36,311

Solution 1

Ok. My problem was hidden in the code i didnt post.

I thought this detailsService is only to get additional details but it is used for the login itself.

I had "jdbcAuthentication" configured additionally and spring seemed to use this always.

Now that i only got the detailsService configured everything works fine.

edit.:

so i only had to delete this code:

auth.jdbcAuthentication() .dataSource(dataSource)
     * .passwordEncoder(passwordEncoder) .usersByUsernameQuery(
//   ....

And now it also works with my code in the question above.

Solution 2

Create Extention class:

public class CustomUserDetails extends org.springframework.security.core.userdetails.User{

    private User user;

    public CustomUserDetails(User user, Collection<? extends GrantedAuthority> authorities) {
        super(user.getName(), user.getPassword(), authorities);
        this.user = user;
    }

    public CustomUserDetails(User user, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
        super(user.getName(), user.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

Than add it to UserDetailsService:

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException, DataAccessException {
    UserDetails userDetails = null;
    User user = userService.getByLogin(login);
    userDetails = new CustomUserDetails(user,
                true, true, true, true,
                getAuthorities(user.getRole()));

    return userDetails;
}

Get it!

 (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()   
Share:
36,311
jvecsei
Author by

jvecsei

Updated on July 09, 2022

Comments

  • jvecsei
    jvecsei almost 2 years

    I am trying to save additional data in de user principal object.

    What i did was:

    implement the "UserDetails" interface to my existing user class where my additional data is saved ( like email address etc. ).

    @Entity
    public class User implements UserDetails {
    

    Then i created a UserDetailsService implementation:

    @Service
    public class UserDetailsServiceImpl implements UserDetailsService {
    
        @Autowired
        UserDAO userDAO;
    
        @Override
        public UserDetails loadUserByUsername(String username)
                throws UsernameNotFoundException {
            User user = userDAO.findOneByUsername(username);
            if (user == null)
                throw new UsernameNotFoundException("username " + username
                        + " not found");
    
            System.out.println("---------------------> FOUND ------------->"
                    + user.getEmail());
    
            return user;
        }
    
    }
    

    Last step was to add the UserDetailsService in my Security configuration.

    @Configuration
    @EnableWebMvcSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    @Autowired
    UserDetailsService userDetailsService;
    
    
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.userDetailsService(userDetailsService());
    // ...
    
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.userDetailsService(userDetailsService());
    // ...
    }
    
    @Override
    protected UserDetailsService userDetailsService() {
        return userDetailsService;
    }
    

    I see in my console that "loadUserByName" gets called twice ( because of the "Found" output ).

    When i try to access the principal object in my controller ->

    System.out.println(SecurityContextHolder.getContext()
                    .getAuthentication().getPrincipal());
    

    I dont get my additional data. When i try to cast it to my User object i get a could not cast exception.

    Is there anything I am missing??

    Thank you in advance.

  • jvecsei
    jvecsei over 9 years
    That didnt change anything. Btw. your last code snippet gives me: "java.lang.ClassCastException: org.springframework.security.core.userdetails.User cannot be cast to ..........CustomUserDetails"
  • hleb.albau
    hleb.albau over 9 years
    can you debug your app and say what class will return SecurityContextHolder.getContext().getAuthentication().getPr‌​incipal() ?
  • jvecsei
    jvecsei over 9 years
    class org.springframework.security.core.userdetails.User