In NixMash Spring we’re using both MySQL and H2Database (two different profiles by environment) for saving user and user authority information. The schema consists of three tables, users, user_authorities and authorities.
The Persistence Models
The Models of User and Authority are not unlike other models, though there are a few differences.
User implements the Spring Security UserDetails Interface.
@Entity
@Table(name = "users")
public class User implements UserDetails
Authority implements the Spring Security GrantedAuthority Interface.
@Entity
@Table(name = "authorities")
public class Authority implements GrantedAuthority
The @ManyToMany Users to Authorities relationship is no different than others, and you’ll notice we’re building a simple Authority Collection here as opposed to Collections of GrantedAuthority objects.
@ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "user_authorities", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "authority_id")) private Collection<Authority> authorities; @Override public Collection<Authority> getAuthorities() { return authorities; }
Saving Authorities on New User Creation
Now we get to the heart of the post, adding multiple authorities on new user creation and populating the necessary database tables, specifically the user_authorities table containing the new user_id and the authority_id(s). The UserService implementation for creating a new user is below.
@Transactional @Override public User create(UserCreateForm form) { User user = new User(); user.setUsername(form.getUsername()); user.setFirstname(form.getFirstname()); user.setLastname(form.getLastname()); user.setEmail(form.getEmail()); user.setPassword(new BCryptPasswordEncoder().encode(form.getPassword())); User saved = userRepository.save(user); for (Authority authority : form.getAuthorities()) { Authority _authority = authorityRepository.findByAuthority(authority.getAuthority()); saved.getAuthorities().add(_authority); } Authentication auth = new UsernamePasswordAuthenticationToken(saved, saved.getPassword(), saved.getAuthorities()); SecurityContextHolder.getContext().setAuthentication(auth); return saved; }
We populate the User Model from our DTO object, the UserCreateForm on which we also perform our validation. (More on validation in a future post.)
We create a new User object upon userRepository.save(), then add the Authorities as normally. To update the Security Context we set the new user authentication and return with a fully Authenticated Environment with a big Hello, Bob Cratchet! waiting for us in the header.
All of the code described in the post is available in the v0.1.6 branch of Spring NixMash on GitHub.