Spring Security - Rollen en privileges

1. Overzicht

In dit artikel wordt de serie Registratie bij Spring Security voortgezet met een blik op de juiste implementatie Rollen en privileges.

2. GebruikerRol en Voorrecht

Laten we eerst beginnen met onze entiteiten. We hebben drie hoofdentiteiten:

  • de Gebruiker
  • de Rol - dit vertegenwoordigt de rollen op hoog niveau van de gebruiker in het systeem; elke rol heeft een set privileges op laag niveau
  • de Voorrecht - vertegenwoordigt een laag niveau, granulair privilege / autoriteit in het systeem

Hier is de gebruiker:

@Entity openbare klasse Gebruiker {@Id @GeneratedValue (strategie = GenerationType.AUTO) privé Lange id; private String voornaam; private String achternaam; privé String-e-mail; privé String-wachtwoord; private boolean ingeschakeld; privé booleaans tokenExpired; @ManyToMany @JoinTable (name = "users_roles", joinColumns = @JoinColumn (name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn (name = "role_id", referencedColumn) naamverzameling = "id") ; }

Zoals u kunt zien, bevat de gebruiker de rollen, maar ook enkele aanvullende details die nodig zijn voor een goed registratiemechanisme.

Volgende - hier is de rol:

@Entity openbare klasse Rol {@Id @GeneratedValue (strategy = GenerationType.AUTO) privé Lange id; private String naam; @ManyToMany (mappedBy = "rollen") gebruikers van privécollecties; @ManyToMany @JoinTable (name = "rolls_privileges", joinColumns = @JoinColumn (name = "role_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn (name = "privilege_id", referencedColumn )Name = "id") ; }

En tenslotte het privilege:

@ Entity public class Privilege {@Id @GeneratedValue (strategy = GenerationType.AUTO) privé Lange id; private String naam; @ManyToMany (mappedBy = "privileges") privéverzamelingsrollen; }

Zoals u kunt zien, kijken we zowel naar de gebruikersrol als naar de rolprivilege-relaties veel-op-veel bidirectioneel.

3. Stel rechten en rollen in

Vervolgens - laten we ons concentreren op een vroege configuratie van de privileges en rollen in het systeem.

We koppelen dit aan het opstarten van de applicatie en gebruiken een ApplicationListener Aan ContextRefreshedEvent om onze initiële gegevens bij het starten van de server te laden:

@Component openbare klasse SetupDataLoader implementeert ApplicationListener {boolean alSetup = false; @Autowired privé UserRepository userRepository; @Autowired privé RoleRepository roleRepository; @Autowired privé PrivilegeRepository privilegeRepository; @Autowired privé PasswordEncoder wachtwoordEncoder; @Override @Transactional public void onApplicationEvent (ContextRefreshedEvent-gebeurtenis) {if (alSetup) terugkeer; Privilege readPrivilege = createPrivilegeIfNotFound ("READ_PRIVILEGE"); Privilege writePrivilege = createPrivilegeIfNotFound ("WRITE_PRIVILEGE"); Lijst adminPrivileges = Arrays.asList (readPrivilege, writePrivilege); createRoleIfNotFound ("ROLE_ADMIN", adminPrivileges); createRoleIfNotFound ("ROLE_USER", Arrays.asList (readPrivilege)); Rol adminRole = roleRepository.findByName ("ROLE_ADMIN"); Gebruiker gebruiker = nieuwe gebruiker (); user.setFirstName ("Test"); user.setLastName ("Test"); user.setPassword (passwordEncoder.encode ("test")); user.setEmail ("[e-mail beschermd]"); user.setRoles (Arrays.asList (adminRole)); user.setEnabled (true); userRepository.save (gebruiker); alSetup = true; } @Transactional Privilege createPrivilegeIfNotFound (String naam) {Privilege privilege = privilegeRepository.findByName (naam); if (privilege == null) {privilege = new Privilege (name); privilegeRepository.save (privilege); } terugkeerprivilege; } @Transactional Role createRoleIfNotFound (Stringnaam, verzamelingsrechten) {Rolrol = roleRepository.findByName (naam); if (role == null) {role = nieuwe rol (naam); role.setPrivileges (privileges); roleRepository.save (rol); } terugkeerrol; }}

Dus, wat gebeurt er tijdens deze eenvoudige installatiecode? Niets ingewikkelds:

  • we creëren de privileges
  • we maken de rollen aan en wijzen de privileges eraan toe
  • we maken een gebruiker aan en wijzen er een rol aan toe

Merk op hoe we een al ingesteld vlag naar bepalen of de installatie moet worden uitgevoerd of niet. Dit komt simpelweg omdat, afhankelijk van het aantal contexten dat u in uw applicatie hebt geconfigureerd, het ContextRefreshedEvent kan meerdere keren worden afgevuurd. En we willen dat de installatie maar één keer wordt uitgevoerd.

Twee korte opmerkingen hier - ten eerste over terminologie. We gebruiken de Privilege - Rol termen hier, maar in het voorjaar zijn deze iets anders. In het voorjaar wordt ons voorrecht Rol genoemd, en ook wel een (toegekende) autoriteit - wat enigszins verwarrend is. Voor de uitvoering natuurlijk geen probleem, maar zeker het vermelden waard.

Ten tweede - deze Spring Roles (onze privileges) hebben een voorvoegsel nodig; standaard is dat voorvoegsel "ROLE", maar het kan worden gewijzigd. We gebruiken dat voorvoegsel hier niet, alleen om het simpel te houden, maar houd er rekening mee dat als u het niet expliciet wijzigt, dit vereist zal zijn.

4. Aangepast UserDetailsService

Laten we nu eens kijken naar het authenticatieproces.

We gaan zien hoe we de gebruiker kunnen ophalen binnen onze gewoonte UserDetailsService, en hoe u de juiste set bevoegdheden kunt toewijzen aan de rollen en bevoegdheden die de gebruiker heeft toegewezen:

@Service ("userDetailsService") @Transactional openbare klasse MyUserDetailsService implementeert UserDetailsService {@Autowired privé UserRepository userRepository; @Autowired privé IUserService-service; @Autowired privé MessageSource-berichten; @Autowired privé RoleRepository roleRepository; @Override openbare UserDetails loadUserByUsername (String e-mail) genereert UsernameNotFoundException {User user = userRepository.findByEmail (e-mail); if (user == null) {retourneer nieuwe org.springframework.security.core.userdetails.User ("", "", true, true, true, true, getAuthorities (Arrays.asList (roleRepository.findByName ("ROLE_USER") ))); } retourneer nieuwe org.springframework.security.core.userdetails.User (user.getEmail (), user.getPassword (), user.isEnabled (), true, true, true, getAuthorities (user.getRoles ())); } privéverzameling getAuthorities (verzamelingsrollen) {retourneer getGrantedAuthorities (getPrivileges (rollen)); } private List getPrivileges (Collectierollen) {List privileges = new ArrayList (); Lijstverzameling = nieuwe ArrayList (); voor (Rolrol: rollen) {collection.addAll (role.getPrivileges ()); } voor (Privilege-item: verzameling) {privileges.add (item.getName ()); } terugkeerprivileges; } private List getGrantedAuthorities (List-privileges) {List-autoriteiten = nieuwe ArrayList (); voor (String privilege: privileges) {autoriteiten.add (nieuwe SimpleGrantedAuthority (privilege)); } terugkeerautoriteiten; }}

Het interessante dat hier moet worden gevolgd, is hoe de privileges (en rollen) worden toegewezen aan GrantedAuthority-entiteiten.

Deze mapping maakt de volledige beveiligingsconfiguratie zeer flexibel en krachtig - u kunt rollen en privileges zo gedetailleerd als nodig combineren en matchen, en aan het einde worden ze correct toegewezen aan autoriteiten en teruggestuurd naar het framework.

5. Gebruiker Registratie

Laten we tot slot eens kijken naar de registratie voor een nieuwe gebruiker.

We hebben gezien hoe setup werkt om de gebruiker aan te maken en er rollen (en privileges) aan toewijst - laten we nu eens kijken hoe dit moet gebeuren tijdens de registratie van een nieuwe gebruiker:

@Override public User registerNewUserAccount (UserDto accountDto) gooit EmailExistsException {if (emailExist (accountDto.getEmail ())) {throw nieuwe EmailExistsException ("Er is een account met dat e-mailadres:" + accountDto.getEmail ()); } Gebruiker gebruiker = nieuwe gebruiker (); user.setFirstName (accountDto.getFirstName ()); user.setLastName (accountDto.getLastName ()); user.setPassword (wachtwoordEncoder.encode (accountDto.getPassword ())); user.setEmail (accountDto.getEmail ()); user.setRoles (Arrays.asList (roleRepository.findByName ("ROLE_USER"))); return repository.save (gebruiker); }

Bij deze eenvoudige implementatie gaan we ervan uit dat een standaardgebruiker wordt geregistreerd, dus het ROLE_USER rol is eraan toegewezen.

Natuurlijk kan complexere logica eenvoudig op dezelfde manier worden geïmplementeerd - ofwel door meerdere, hardcoded registratiemethoden te hebben, of door de client het type gebruiker te laten sturen dat wordt geregistreerd.

6. Conclusie

In deze zelfstudie hebben we geïllustreerd hoe u rollen en privileges met JPA implementeert voor een door Spring Security ondersteund systeem.

De volledige implementatie van deze zelfstudie over Registratie met Spring Security is te vinden in het GitHub-project - dit is een op Maven gebaseerd project, dus het zou gemakkelijk te importeren en uit te voeren moeten zijn zoals het is.


$config[zx-auto] not found$config[zx-overlay] not found