Home > Software design >  spring boot security- adding custom role names
spring boot security- adding custom role names

Time:12-04

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 are USERS
  • all teacher are ADMINS
  • there is only 1 (few) principal ..and also ADMIN (and also teacher ?? ...please! school systems vary widely...;-)
  • principal is the only one who has a comma in his (authority) list!?
  • (no student is teacher!?)

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)

  • Related