Tavaszi biztonság - szerepek és kiváltságok

1. Áttekintés

Ez a cikk folytatja a Regisztráció a Spring Security-vel sorozatát, áttekintve a megfelelő végrehajtást Szerepek és kiváltságok.

2. FelhasználóSzerep és Kiváltság

Először is kezdjük az entitásainkkal. Három fő entitásunk van:

  • a Felhasználó
  • a Szerep - ez a felhasználó magas szintű szerepét képviseli a rendszerben; minden szerepkör alacsony szintű privilégiumokkal rendelkezik
  • a Kiváltság - alacsony szintű, részletezett kiváltságot / jogkört képvisel a rendszerben

Itt van a felhasználó:

@Entity public class User {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; privát karakterlánc keresztnév; privát karakterlánc vezetéknév; privát karakterlánc e-mail; privát karakterlánc jelszó; privát boolean engedélyezve; privát logikai tokenExperired; @ManyToMany @JoinTable (name = "users_roles", joinColumns = @JoinColumn (name = "user_id", referentedColumnName = "id"), inverseJoinColumns = @JoinColumn (name = "role_id", referentedColumnName = "id")) magángyűjteményi szerepkörök ; }

Amint láthatja, a felhasználó tartalmazza a szerepeket, de néhány további részletet is, amelyek szükségesek a megfelelő regisztrációs mechanizmushoz.

Következő - itt van a szerep:

@Entity public class Role {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; privát karakterlánc neve; @ManyToMany (mappedBy = "szerepek") privát gyűjtemény felhasználói; @ManyToMany @JoinTable (név = "szerepek_jogosultságok", joinColumns = @JoinColumn (név = "szerep_id", hivatkozott oszlopNév = "id"), inverseJoinColumns = @JoinColumn (név = "privilege_id", hivatkozottColumnName = "id") privát gyűjtemény ; }

És végül a kiváltság:

@Entity public class Privilege {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; privát karakterlánc neve; @ManyToMany (mappedBy = "privilégiumok") magángyűjteményi szerepkörök; }

Amint láthatja, mind a Felhasználói szerep, mind a Szerepjogosultság kapcsolatokat figyelembe vesszük sok-sok kétirányú.

3. Jogosultságok és szerepkörök beállítása

Következő - összpontosítsunk a privilégiumok és szerepek korai beállítására a rendszerben.

Ezt összekapcsoljuk az alkalmazás indításával, és egy ApplicationListener tovább ContextRefreshedEvent kezdeti adataink betöltésére a szerver indításakor:

A @Component public class SetupDataLoader végrehajtja az ApplicationListener {boolean jubaSetup = hamis; @Autowired private UserRepository userRepository; @Autowired private RoleRepository roleRepository; @Autowired privát PrivilegeRepository privilegeRepository; @Autowired private PasswordEncoder passwordEncoder; @Override @Transactional public void onApplicationEvent (ContextRefreshedEvent event) {if (alreadySetup) return; Privilege readPrivilege = createPrivilegeIfNotFound ("READ_PRIVILEGE"); Privilege writePrivilege = createPrivilegeIfNotFound ("WRITE_PRIVILEGE"); List adminPrivileges = Arrays.asList (readPrivilege, writePrivilege); createRoleIfNotFound ("ROLE_ADMIN", adminPrivileges); createRoleIfNotFound ("ROLE_USER", Tömbök.asList (readPrivilege)); Szerep adminRole = roleRepository.findByName ("ROLE_ADMIN"); Felhasználó felhasználó = új Felhasználó (); user.setFirstName ("Teszt"); user.setLastName ("Teszt"); user.setPassword (passwordEncoder.encode ("teszt")); user.setEmail ("[e-mail védett]"); user.setRoles (Arrays.asList (adminRole)); user.setEnabled (true); userRepository.save (felhasználó); márSetup = true; } @Transactionional Privilege createPrivilegeIfNotFound (String name) {Privilege privilege = privilegeRepository.findByName (name); if (privilege == null) {privilege = új privilégium (név); privilegeRepository.save (privilégium); } visszatérési jogosultság; } @Transactional Role createRoleIfNotFound (Karakterlánc neve, Gyűjteményi jogosultságok) {Szerepkör = roleRepository.findByName (név); if (role == null) {role = new Role (név); role.setPrivileges (privilégiumok); roleRepository.save (szerep); } visszatérési szerep; }}

Tehát mi történik ezen az egyszerű telepítési kódon? Semmi bonyolult:

  • létrehozzuk a kiváltságokat
  • létrehozzuk a szerepeket, és hozzájuk rendeljük a kiváltságokat
  • létrehozunk egy felhasználót, és szerepet rendelünk hozzá

Vegye figyelembe, hogyan használjuk az márSetup zászló to határozza meg, hogy a telepítésnek futtatnia kell-e vagy sem. Ez egyszerűen azért van, mert attól függően, hogy hány kontextust konfigurált az alkalmazásában - a ContextRefreshedEvent többször kirúghatják. És csak azt akarjuk, hogy a beállítást egyszer hajtják végre.

Két gyors megjegyzés itt - először a terminológiáról. Használjuk a Kiváltság - szerep itt, de tavasszal ezek kissé eltérnek. Tavasszal privilégiumunkat szerepként, valamint (adott) jogosultságként emlegetik - ami kissé zavaró. Természetesen nem jelent problémát a megvalósítás szempontjából, de mindenképpen érdemes megjegyezni.

Másodszor - ezekhez a tavaszi szerepekhez (kiváltságaink) előtagra van szükség; alapértelmezés szerint ez az előtag „ROLE”, de megváltoztatható. Itt nem ezt az előtagot használjuk, csak azért, hogy a dolgok egyszerűek legyenek, de ne feledje, hogy ha nem változtatja meg kifejezetten, akkor erre szükség lesz.

4. Egyedi UserDetailsService

Most - nézzük meg a hitelesítési folyamatot.

Meglátjuk, hogyan lehet a felhasználót a szokásaink szerint lehívni UserDetailsService, valamint a megfelelő jogosultsági halmaz feltérképezése a felhasználó által kiosztott szerepek és jogosultságok alapján:

@Service ("userDetailsService") @Transactional public class A MyUserDetailsService megvalósítja a UserDetailsService {@Autowired private UserRepository userRepository; @Autowired privát IUserService szolgáltatás; @Autowired privát MessageSource üzenetek; @Autowired private RoleRepository roleRepository; @A nyilvános UserDetails felülbírálása loadUserByUsername (karakterlánc e-mail) dob felhasználónévNotFoundException {Felhasználó felhasználó = userRepository.findByEmail (e-mail); if (user == null) {return new org.springframework.security.core.userdetails.User ("", "", true, true, true, true, getAuthorities (Arrays.asList (roleRepository.findByName ("ROLE_USER")) ))); } return new org.springframework.security.core.userdetails.User (user.getEmail (), user.getPassword (), user.isEnabled (), true, true, true, getAuthorities (user.getRoles ())); } privát gyűjtemény getAuthorities (gyűjtemény szerepek) {return getGrantedAuthorities (getPrivileges (szerepek)); } privát Lista getPrivileges (Gyűjteményi szerepkörök) {List privilégiumok = új ArrayList (); Lista gyűjtemény = new ArrayList (); for (Szerepszerep: szerepek) {collection.addAll (role.getPrivileges ()); } a (Privilege item: collection) {privileges.add (item.getName ()) számára; } visszatérési jogosultságok; } private List getGrantedAuthorities (List privilégiumok) {List hatóságok = new ArrayList (); for (String privilege: privilégiumok) {hatóságok.add (új SimpleGrantedAuthority (privilégium)); } visszatérési hatóságok; }}

Az itt követendő érdekesség az, hogy a privilégiumokat (és szerepeket) miként hozzárendelik a GrantedAuthority entitásokhoz.

Ez a leképezés elkészíti a teljes biztonsági konfigurációt rendkívül rugalmas és erőteljes - a szerepeket és a privilégiumokat a lehető legrészletesebben keverheti és illesztheti, és a végén azokat helyesen hozzárendelik a hatóságokhoz, és visszatérnek a keretrendszerhez.

5. Felhasználó Bejegyzés

Végül - vessünk egy pillantást az új felhasználó regisztrációjára.

Láttuk, hogyan halad a telepítés a Felhasználó létrehozása során, és szerepeket (és jogosultságokat) rendel hozzá hozzá - most nézzük meg, hogyan kell ezt megtenni egy új felhasználó regisztrációja során:

@Orride public User registerNewUserAccount (UserDto accountDto) dobja az EmailExistsException {if (emailExist (accountDto.getEmail ())) {dobja új EmailExistsException ("Van egy fiók azzal az e-mail címmel:" + accountDto.getEmail ()); } Felhasználó felhasználó = új Felhasználó (); user.setFirstName (accountDto.getFirstName ()); user.setLastName (accountDto.getLastName ()); user.setPassword (passwordEncoder.encode (accountDto.getPassword ())); user.setEmail (accountDto.getEmail ()); user.setRoles (Arrays.asList (roleRepository.findByName ("ROLE_USER"))); return repository.save (felhasználó); }

Ebben az egyszerű megvalósításban feltételezzük, hogy egy szabványos felhasználót regisztrálnak, ezért a ROLE_USER szerepet rendelnek hozzá.

Természetesen a bonyolultabb logika könnyen megvalósítható ugyanúgy - akár több, kemény kódolású regisztrációs módszerrel, akár annak lehetővé tételével, hogy az ügyfél elküldje a regisztrált felhasználó típusát.

6. Következtetés

Ebben az oktatóanyagban bemutattuk, hogyan lehet megvalósítani a szerepeket és privilégiumokat a JPA-val egy Spring Security által támogatott rendszerhez.

A teljes végrehajtása A regisztráció a Spring Security oktatóanyaggal megtalálható a GitHub projektben - ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.