First of all, both approaches are used for different purposes and are not interchangeable.
Case 1:
UserDetailsService used exclusively as a DAO to search for user information about your authentication and, based on this authenticated user, authentication within the UserDetailsService does not require authentication, but only access to data. Specifications clearly indicate this. This is what you are looking for.
Case 2:
AuthentictionProvider , on the other hand, is used to provide a custom authentication method, for example, if you want to configure authentication in fields other than the username and password that you can do by implementing AuthentictionProvider and providing this object to your AuthenticationManagerBuilder . I do not think that this is what you want to do in the project. You are simply trying to implement your authentication based on users stored in the database using the username and password, which are used by default. In the above example, Case 1 , where you implemented only a UserDetailsService , an AuthentictionProvider instance was created for you in the AuthenticationManager container, and it was a DaoAuthenticationProvider , because you provided a UserDetailsService, which is nothing more than a DAO on your system that is used to fetch the user for authentication.
Now to your implementation, in your configuration instead:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {
do something like that
@Autowired private CustomUserDetailsService userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); }
and your CustomUserDetailsService should implement org.springframework.security.core.userdetails.UserDetailsService
@Service public class CustomUserDetailsService implements UserDetailsService { private final AdminRepository userRepository; @Autowired public CustomUserDetailsService(AdminRepository userRepository) { this.userRepository = userRepository; } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Admin user = userRepository.findByLogin(username); if (user == null) { throw new UsernameNotFoundException(String.format("User %s does not exist!", username)); } return new UserRepositoryUserDetails(user); } private final static class UserRepositoryUserDetails extends Admin implements UserDetails { private static final long serialVersionUID = 1L; private UserRepositoryUserDetails(User user) { super(user); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return AuthorityUtils.createAuthorityList("ROLE_USER"); } @Override public String getUsername() { return getLogin();
Of course, the implementation is up to you, but you should be able to provide the user password and other methods in this interface based on the received user (Admin.class in your case). Hope it helps. I did not run this example, so if I made some typos, and ask if something is working. I would also get rid of this "AuthentictionProvider" from your project if you do not need it.
Here you will get documentation: http://docs.spring.io/spring-security/site/docs/4.0.0.RC1/reference/htmlsingle/#tech-userdetailsservice
After comments: You can install PasswordEncoder in your configuration method without any hassle:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); } @Bean public PasswordEncoder passwordEncoder(){ PasswordEncoder encoder = new BCryptPasswordEncoder(); return encoder; }
This can be done because you are accessing the AbstractDaoAuthenticationConfigurer returned from auth.userDetailsService(userDetailsService) and it allows you to configure the DaoAuthenticationProvider , which is your provider of choice, when you decide to use UserDetailsService . You're right. PasswordEncoder set to AuthenticationProvider , but you don't need to implement AuthenticationProvider just use the convineince object that comes back from auth.userDetailsService(userDetailsService) and set your encoder on that object, which will pass it to AuthenticationPriovider in your case, DaoAuthenticationProvider , which was already created for you. Just as the roadrunner mentioned in the comments, you very rarely need to implement your own AuthenticationProvider , usually most authentication configuration settings can be done using AbstractDaoAuthenticationConfigurer , which, as mentioned above, is returned from auth.userDetailsService(userDetailsService) .
"And if I ever wanted to add password encryption. And if I ever wanted to do another authentication (for example, check if the user is locked, the user is active, is still registered, etc. [excluding password hashing] ) will use AuthenticationProvider. "
No, this is done for you as part of the standard authentication mechanism http://docs.spring.io/autorepo/docs/spring-security/3.2.0.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html If you look at the UserDetails interface, you will see that if any of the above methods returns, then false authentication will fail. The implementation of AuthenticationProvider really necessary in very unusual cases. All standard materials are heavily coated.