Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security/Spring Boot - How to set ROLES for users

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.

like image 864
Jiji Avatar asked Jun 03 '16 12:06

Jiji


4 Answers

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.

like image 154
DiveInto Avatar answered Sep 19 '22 01:09

DiveInto


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:

Spring Security Related 1

Spring Security Related 2

like image 39
Ajay Kumar Avatar answered Sep 19 '22 01:09

Ajay Kumar


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());
}
like image 44
Siddhey Sankhe Avatar answered Sep 21 '22 01:09

Siddhey Sankhe


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

like image 30
Carlos Flores Avatar answered Sep 18 '22 01:09

Carlos Flores