Spring Security/Spring Boot - How to set ROLES for users
Solution 1
You should fill in the content of role by yourself when creating your UserDetails:
public class SecurityUser implements UserDetails{
String ROLE_PREFIX = "ROLE_";
String userName;
String password;
String role;
public SecurityUser(String username, String password, String role){
this.userName = username;
this.password = password;
this.role = role;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> list = new ArrayList<GrantedAuthority>();
list.add(new SimpleGrantedAuthority(ROLE_PREFIX + role));
return list;
}
Basically, what you need to do is override method: getAuthorities
, and fill in the content of your role field into the GrantedAuthority
list.
Solution 2
What Divelnto, zapl and thorinkor said is right. But the question should be about "Role" and NOT "Roles". OR, if you are having users and roles into one table, its a bad design. You might want to take a relook at your design approach. You should have a separate role entity. And in your UserService you can do something like:
AppUser user = userRepository.findByUsername(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>(); // use list if you wish
for (AppRole role : user.getRoles()) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(
user.getUsername(),
user.getPassword(),
grantedAuthorities
);
Samples: sample1 sample2 sample3
In DB, you can store role name as - (e.g.) ADMIN/EDITOR/VIEWER in the database or store roles as ROLE_ADMIN/ROLE_... then you might wanna use hasRole/hasAuthoriy. Hope it helps.
For reference, take a look at here:
Solution 3
For adding Roles you need to have a table containing username and its corresponding role.
Suppose a user has two roles namely, ADMIN and USER
One User can have multiple roles.
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
final List<SimpleGrantedAuthority> authorities = new LinkedList<>();
if (enabled) {
if (this.getUser().isAdmin()) {
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
}
return authorities;
}
This can be called as,
private UsernamePasswordAuthenticationToken getAuthentication(
final String token, final HttpServletRequest req,
final HttpServletResponse res){
return new UsernamePasswordAuthenticationToken(userAccount, null,
userAccount.getAuthorities());
}
Solution 4
You can also used this way to load ROLEs or Authorities using User.builder object. This example is receiving token from http request and it gets the list o ROLES inside TOKEN. You can have a simple list of strings containing the roles you need and just loaded to the UserDetail implementation:
private UserDetails userDetails(final Claims claims) {
UserDetails userDetails = User.builder()
.username(resolveUserName(claims))
.password(resolveUserPassword())
.roles(userRoles(claims))
.build();
return userDetails;
}
where userRoles(claims) is just returning an array of strings with all Roles you need.
I hope it helps
Related videos on Youtube
Comments
-
Jiji almost 2 years
When I logged in using security, I cannot use the
request.isUserInRole()
method. I think the roles of the users was not set.This is my Security Configuration:
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled=true) @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; @Autowired private UserDetailsServiceImplementation userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/signup").permitAll() .antMatchers("/").permitAll() //.antMatchers("/first").hasAuthority("Service_Center") .antMatchers("/login").permitAll() .anyRequest().fullyAuthenticated() .and().formLogin() .loginPage("/login") .usernameParameter("email") .passwordParameter("password") .defaultSuccessUrl("/default") .failureUrl("/login?error").permitAll() .and().logout() .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .logoutSuccessUrl("/login?logout") .deleteCookies("JSESSIONID") .invalidateHttpSession(true).permitAll(); } @Autowired public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } }
This is my
User
entity:@Entity @Table(name="user") public class User implements Serializable{ /** * */ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name="user_id") private Long userID; @Column(name="email_address", nullable = false, unique = true) private String emailAddress; @Column(name="password") private String password; @Column(name = "role", nullable = false) @Enumerated(EnumType.STRING) private Role role; public User() { super(); } public User(String emailAddress, String password) { this.emailAddress = emailAddress; this.password = password; } public Long getUserID() { return userID; } public void setUserID(Long userID) { this.userID = userID; } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } @Override public String toString() { return "User [userID=" + userID + ", emailAddress=" + emailAddress + ", password=" + password + ", role=" + role + "]"; } public UserDetails toCurrentUserDetails() { return CurrentUserDetails.create(this); } }
This is my enum
Role
:public enum Role { Fleet_Company, Service_Center, Admin }
This is my
UserDetailsServiceImplementation
:@Component public class UserDetailsServiceImplementation implements UserDetailsService { @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { if ( username == null || username.isEmpty() ){ throw new UsernameNotFoundException("username is empty"); } User foundUser = userRepository.findByEmailAddress(username); if( foundUser != null ){ System.out.println("FOUND"); return foundUser.toCurrentUserDetails(); } throw new UsernameNotFoundException( username + "is not found"); } }
This is the class that implements
UserDetails
:public class CurrentUserDetails implements UserDetails { private Long userID; private String emailAddress; private String password; private Role role; public CurrentUserDetails(Long userID, String emailAddress, String password, Role role) { super(); this.userID = userID; this.emailAddress = emailAddress; this.password = password; this.role = role; } /* public static UserDetails create(Users entity) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); for(Authorities auth: entity.getAuthorities()){ authorities.add(new SimpleGrantedAuthority(auth.getId().getAuthority())); } return new MyUserDetail(entity.getUserId(), entity.getLoginId(), entity.getPassword(), entity.getDisplayName(), authorities); }*/ public Long getUserID(){ return this.userID; } public Role getRole(){ return this.role; } @Override public String getPassword() { return this.password; } public String getEmailAddress() { return this.emailAddress; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } public static UserDetails create(User entity) { System.out.println(entity.getUserID()+ entity.getEmailAddress()+ entity.getPassword()+ entity.getRole()); return new CurrentUserDetails(entity.getUserID(), entity.getEmailAddress(), entity.getPassword(), entity.getRole()); } @Override public Collection<? extends GrantedAuthority> getAuthorities() { // TODO Auto-generated method stub return null; } @Override public String getUsername() { // TODO Auto-generated method stub return null; } }
So basically, we can see that I only have one table on my MySQL database, it has four columns and one of them is 'role'.
But like what I said, when I use
request.isUserInRole("Service_Center")
, it returns FALSE. And.antMatchers("/first").hasAuthority("Service_Center")
doesn't work either.-
zapl almost 8 yearswhat's the
UserDetailsServiceImplementation
? I believe thats the place that should link your entity to the request principal. -
zapl almost 8 yearsOk, so tracing the issue leads to
CurrentUserDetails.create(this)
. What does that do? -
Jiji almost 8 years@zapl that was the class that implements UserDetails. I edited my post. You can see it now. That's basically all of my Spring Security.
-
zapl almost 8 yearsYou need to return the roles via
getAuthorities()
- stackoverflow.com/questions/19525380/… - spring does not look at your owngetRole
method. -
Jiji almost 8 yearsDoes it automatically sets it via getAuthorities()?
-
-
thorinkor about 7 yearsadding new Role on getAuthorities method? Doesn't look like it is a good idea... You should use
SecurityContextHolder
and do it in separate service. -
rougou over 5 yearsYou said it is bad design to have users and roles in one entity, but your sample code seems to do exactly that... I think it is simpler to have them together if your DB allows that.
-
Ajay Kumar over 5 yearsDon't get me wrong bud.! Do you see a 'column' - "role" in any of the User entities in the samples? Moreover if a User is supposed to have just one role, why you need a role in the first place? Its a wage idea. Instead of using "role" (not "roles") you can put a flag as true/false with if-else condition that will solve the purpose In-My-Humble-Opinion. Thanks.
-
Pavan Kumar over 4 yearsShould role contain ROLE_ prefix? And if the role is ROLE_ADMIN hasRole should specify 'ADMIN' or 'ROLE_ADMIN'?
-
Saroj Kumar Sahoo about 4 yearswhy do we need to add ROLE_PREFIX any specific reason . I have developed one application where I am returning what ever coming from database just split it by comma and I am putting into a variable which has List of GrantedAuthority . But in database we must have to specify ROLE_PREFIX .I want to understand why
-
Malik Firose about 3 yearsSpring uses it for some internal purposes. Inside the User.UserBuilder roles as you can see spring creates the SimpleGrantedAuthority with the ROLE prefix like authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); As long as if you use the builder you don't need to give the prefix.
-
BendaThierry.com about 2 yearsIt depends about your application needs and functionnal point of view. Let's explain a bit about that. Some applications handle one role for one user, and roles are following hierachical inheritance between them. Some applications handle multiples roles for one same user and multiple authorities for one same user. So none of you has wrong and none of you are right. It depends.