Reputation: 127
I have 4 different type of users. Every type have own role and additional attributes. User is parent, and 3 inheritors.
Also I use Spring Data.
In which way I can implement UserDetailsService to use 4 different types of users?
Now I have:
@Inheritance(strategy = InheritanceType.JOINED)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Long id;
private String username;
private String password;
private String email;
@ManyToMany
@JoinTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles;
}
And
public class Employee extends User implements Serializable {
private static final long serialVersionUID = 1L;
private String fullName;
@ManyToMany(mappedBy = "employees")
private Set<Project> projects;
@OneToMany(mappedBy = "employee")
private Set<Task> tasks;
}
And other.
Upvotes: 2
Views: 9950
Reputation: 5035
Since you are talking about UserDetailsService
I assume that you use Spring Security
. If you only need to authenticate/authorize users, I'm not sure you need the full user management the UserDetailsService
offers. It may be enough to define a single AuthenticationProvider
and to the query here
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@PersistenceContext
private EntityManager entityManager;
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new AuthenticationProvider() {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// Do you database query here
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_")); // list of roles from database
return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(),
authentication.getCredentials(), authorities);
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
})
}
}
This example is inline and you should probably make the AuthenticationProvider
a real class.
The AuthenticationProvider
is called with an unauthenticated Authentication
, which has been created by a filter, typically BasicAuthenticationFilter
or UsernamePasswordAuthenticationFilter
. After this, the Authentication
is given to the ProviderManager
which ask each of the AuthenticationProvider
if they can authenticate this type of Authentication
(this is what the supports() method is for). Once a suitable AuthenticationProvider
is found, it is asked to authenticate — This is where you do your database lookup and find the roles from the database, and construct a new Authentication
with the list of GrantedAuthorities
based on the roles from the database.
Be aware that you should put "ROLE_" in front of the roles (unless you store them like that), otherwise it will not work with the declarative access configured using HttpSecurity
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/","/home").permitAll()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
// more lines
}
Here ADMIN maps to the GrantedAuthority
ROLE_ADMIN.
Upvotes: 1