I am following a spring boot JPA authentication security tutorial. I have set up authentication for USERS and ADMINS.
however in MySQL database i have custom roles such as 'principal' and 'teacher' and 'student'
How can I add these custom roles to my authentication.
I am assuming I need to do this in the UserDetails class. here is my code so far
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
public class UserDetails implements UserDetails {
private String username;
private String password;
private boolean active;
private List<GrantedAuthority> authorities;
public MyUserDetails(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.active = user.isActive();
this.authorities = Arrays.stream(user.getTheType().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return active;
}
}
CodePudding user response:
for the tutorial/lesson, it is ok when you (try to) rename/refactor:
- the roles (useres, admins ... roles or authorities? tomayto, tomahto (just prepend/cutoff a
ROLE_
;) - the db columns.
But the least intrusive and quite efficient (for only 2 roles/few combinations) approach would be like:
// adjust to requirements:
static final String REGEX_USERS = "student"; // exact match
static final String REGEX_ADMINS = "(teacher|principal)"; // group OR match
static final String AUTH_ADMINS = "ADMINS";
static final String AUTH_USERS = "USERS";
...and then:
this.authorities = Arrays.stream(
user
.getTheType()
.replaceAll(REGEX_USERS, USERS)
.replaceAll(REGEX_ADMINS, ADMINS)
.split(",")
)
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
A standalone test:
package com.example.demo;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
class TestO {
static final String REGEX_USERS = "student";
static final String REGEX_ADMINS = "(teacher|principal)";
static final String AUTH_ADMINS = "ADMINS";
static final String AUTH_USERS = "USERS";
public static void main(String[] args) {
String testData1 = "student";
String testData2 = "teacher,principal";
List<GrantedAuthority> result1 = Arrays.stream(testData1
.replaceAll(REGEX_USERS, AUTH_USERS)
.replaceAll(REGEX_ADMINS, AUTH_ADMINS)
.split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
System.out.format("%s%n", result1);
List<GrantedAuthority> result2 = Arrays.stream(testData2
.replaceAll(REGEX_USERS, AUTH_USERS)
.replaceAll(REGEX_ADMINS, AUTH_ADMINS)
.split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
System.out.format("%s%n", result2);
}
}
Prints:
[USERS]
[ADMINS, ADMINS]
If my assumptions(!) about role-mappings were correct:
- all
student
areUSERS
- all
teacher
areADMINS
- there is only 1 (few)
principal
..and alsoADMIN
(and alsoteacher
?? ...please! school systems vary widely...;-) principal
is the only one who has a comma in his (authority) list!?- (no
student
isteacher
!?)
Then probably (and in any "granted authority specific" case):
private java.util.Set<GrantedAuthority> authorities;
...then also:
Collectors.toSet() // refacotrings
is preferrable! (What is the difference between Set and List? !;)
So:
Set<GrantedAuthority> result2 = Arrays.stream(testData2
.replaceAll(REGEX_USERS, "USERS")
.replaceAll(REGEX_ADMINS, "ADMINS")
.split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toSet());
System.out.format("%s%n", result2);
Prints:
...
[ADMINS]
See also (reg. efficient string replacement):
Java Replacing multiple different substring in a string at once (or in the most efficient way)