If you’re using Spring Roo and Spring Data JPA, then implementing your own Spring Security authentication provider in a Spring MVC application is pretty simple to do.
The first thing you need is an entity class that represents the user table in your database. That’s the table where usernames and passwords reside. Creating an entity with Roo is easy. The first thing you have to do after you’ve created your entity is update it to implement Spring Security’s UserDetails interface. Your resulting entity should look something like this. This example is very basic.
@RooJavaBean
@RooToString
@RooJpaEntity(table = "USERS", versionField = "")
public class Person implements UserDetails {
@Id
private String username;
private String password;
public Collection<? extends GrantedAuthority> getAuthorities() {
// your logic goes here
}
public boolean isAccountNonExpired() {
// your logic goes here
}
public boolean isAccountNonLocked() {
// your logic goes here
}
public boolean isCredentialsNonExpired() {
// your logic goes here
}
public boolean isEnabled() {
// your logic goes here
}
}
As you can see, there’s not much to it. Since we’re using Roo, the getters/setters for username and password are created for us. The UserDetails interface requires us to have a getUsername() and getPassword() method, but since our private fields are called username and password, the required getters are generated by Roo.
Next we need a Person repository. Creating this repository using Spring Roo is also very easy. Using Spring Data JPA, the resulting repository interface looks like the following:
@RooJpaRepository(domainType = Person.class)
public interface PersonRepository {
}
Not much to it indeed. Underneath the covers, the Roo generated ITD takes care of annotating our repository with @Repository and extending Spring Data JPA’s JpaRepository and JpaSpecificationExecutor interfaces.
Now that we have our UserDetails implementation and our Spring Data JPA repository, we need to implement Spring Security’s UserDetailsService interface. This interface is quite simple in that you only need to implement one method called “loadUserByUsername”. Simply injecting our newly created PersonRepository, we can very easily return the Person record we find using the username passed to “loadUserByUsername”. Our repository returns Person instances, but the “loadUserByUsername” method returns an instance of UserDetails. If you remember, our Person entity implements UserDetails, therefore returning a Person instance from the PersonRepository satisfies our UserDetailsService implementaiton.
@Service
public class MyUserDetailsService implements UserDetailsService {
@Inject
private PersonRepository personRepository;
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
return personRepository.findOne(username);
}
}
Finally, all we have to do is update the Roo generated applicationContext-security.xml configuration file to use our custom UserDetailsService.
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="myUserDetailService"/>
</authentication-manager>
That’s basically all there is to it. In your application, you’ll have your own logic for loading the user’s granted authorities in the Person entity, so I didn’t go into any details there.
