Úvod do Apache Shiro

1. Prehľad

V tomto článku sa pozrieme na Apache Shiro, všestranný bezpečnostný rámec Java.

Rámec je vysoko prispôsobiteľný a modulárny, pretože ponúka autentifikáciu, autorizáciu, kryptografiu a správu relácií.

2. Závislosť

Apache Shiro má veľa modulov. V tomto výučbe však používame širo-jadro iba artefakt.

Pridajme to k nášmu pom.xml:

 org.apache.shiro shiro-core 1.4.0 

Najnovšiu verziu modulov Apache Shiro nájdete na serveri Maven Central.

3. Konfigurácia bezpečnostného manažéra

The SecurityManager je stredobodom rámca Apache Shiro. Aplikácie budú mať zvyčajne spustenú jednu inštanciu.

V tomto návode preskúmame rámec v prostredí pracovnej plochy. Ak chcete nakonfigurovať rámec, musíme vytvoriť shiro.ini súbor v priečinku prostriedkov s nasledujúcim obsahom:

[users] user = password, admin user2 = password2, editor user3 = password3, autor [role] admin = * editor = články: * autor = články: písať, články: ukladať

The [používatelia] časť shiro.ini konfiguračný súbor definuje poverenia používateľa, ktoré rozpoznáva server SecurityManager. Formát je: principal (username) = heslo, role1, role2,…, role.

Roly a s nimi spojené povolenia sú deklarované v [role] oddiel. The admin role je udelené povolenie a prístup ku každej časti aplikácie. Toto je označené zástupným znakom (*) symbol.

The editor rola má všetky povolenia spojené s článkov kým autor rola môže iba komponovať a uložiť článok.

The SecurityManager sa používa na konfiguráciu SecurityUtils trieda. Z SecurityUtils môžeme získať súčasného používateľa interagujúceho so systémom a vykonávať autentifikačné a autorizačné operácie.

Použime IniRealm načítať naše definície používateľov a rolí z shiro.ini súbor a potom ho použite na konfiguráciu súboru DefaultSecurityManager objekt:

IniRealm iniRealm = nový IniRealm ("classpath: shiro.ini"); SecurityManager securityManager = nový DefaultSecurityManager (iniRealm); SecurityUtils.setSecurityManager (securityManager); Predmet currentUser = SecurityUtils.getSubject ();

Teraz, keď máme SecurityManager ktorý si je vedomý poverenia používateľa a rolí definovaných v shiro.ini súboru, poďme k autentifikácii a autorizácii používateľa.

4. Autentifikácia

V terminológiách Apache Shira, a Predmet je akýkoľvek subjekt interagujúci so systémom. Môže to byť človek, skript alebo klient REST.

Telefonovanie SecurityUtils.getSubject () vráti inštanciu aktuálneho Predmet, tj súčasný užívateľ.

Teraz, keď máme súčasný užívateľ Objekt, môžeme vykonať autentizáciu na dodaných povereniach:

if (! currentUser.isAuthenticated ()) {UsernamePasswordToken token = nový UsernamePasswordToken ("užívateľ", "heslo"); token.setRememberMe (true); try {currentUser.login (token); } catch (UnknownAccountException uae) {log.error ("Username Not Found!", uae); } catch (IncorrectCredentialsException ice) {log.error ("Invalid Credentials!", ice); } catch (LockedAccountException lae) {log.error ("Váš účet je zamknutý!", lae); } catch (AuthenticationException ae) {log.error ("Neočakávaná chyba!", ae); }}

Najskôr skontrolujeme, či aktuálny používateľ ešte nebol autentifikovaný. Potom vytvoríme autentifikačný token s principálom používateľa (používateľské meno) a poverenie (heslo).

Ďalej sa pokúsime prihlásiť pomocou tokenu. Ak sú zadané údaje správne, malo by byť všetko v poriadku.

Pre rôzne prípady existujú rôzne výnimky. Je tiež možné vyvolať vlastnú výnimku, ktorá lepšie vyhovuje požiadavkám aplikácie. To je možné vykonať podtriedou Výnimka z účtu trieda.

5. Povolenie

Autentifikácia sa pokúša overiť totožnosť používateľa, zatiaľ čo autorizácia sa pokúša riadiť prístup k určitým prostriedkom v systéme.

Pripomeňme, že každému používateľovi, ktorého sme si vytvorili v rámci servera, priradíme jednu alebo viac rolí shiro.ini spis. Ďalej v sekcii rolí definujeme rôzne povolenia alebo úrovne prístupu pre každú rolu.

Teraz sa pozrime, ako to môžeme v našej aplikácii použiť na vynútenie kontroly prístupu používateľov.

V shiro.ini súboru, poskytneme správcovi celkový prístup ku každej časti systému.

Editor má úplný prístup ku všetkým zdrojom alebo operáciám, ktoré sa ich týkajú článkov, a autor je obmedzený iba na skladanie a ukladanie článkov iba.

Privítajme súčasného používateľa na základe roly:

if (currentUser.hasRole ("admin")) {log.info ("Vitajte správca"); } else if (currentUser.hasRole ("editor")) {log.info ("Vitajte, redaktor!"); } else if (currentUser.hasRole ("autor")) {log.info ("Vitajte, autor"); } else {log.info („Vitajte, hosť“); }

Teraz sa pozrime, čo má aktuálny používateľ v systéme povolené:

if (currentUser.isPermitted ("articles: compose")) {log.info ("Môžete vytvoriť článok"); } else {log.info ("Nemáte oprávnenie vytvárať článok!"); } if (currentUser.isPermitted ("articles: save")) {log.info ("Môžete ukladať články"); } else {log.info ("Články nemôžete ukladať"); } if (currentUser.isPermitted ("articles: publish")) {log.info ("Môžete publikovať články"); } else {log.info ("Nemôžete publikovať články"); }

6. Konfigurácia sféry

V skutočných aplikáciách budeme potrebovať spôsob, ako získať prihlasovacie údaje používateľa skôr z databázy ako z databázy shiro.ini spis. Tu vstupuje do hry koncept Ríše.

V terminológii Apache Shiro je Realm DAO, ktorý ukazuje na úložisko používateľských poverení potrebných na autentifikáciu a autorizáciu.

Na vytvorenie ríše stačí implementovať Ríša rozhranie. To môže byť únavné; rámec však prichádza s predvolenými implementáciami, z ktorých môžeme podtriedu. Jednou z týchto implementácií je JdbcRealm.

Vytvárame implementáciu vlastnej sféry, ktorá sa rozširuje JdbcRealm triedy a má prednosť pred nasledujúcimi metódami: doGetAuthenticationInfo (), doGetAuthorizationInfo (), getRoleNamesForUser () a getPermissions ().

Vytvorme ríšu podtriedou JdbcRealm trieda:

verejná trieda MyCustomRealm rozširuje JdbcRealm {// ...}

Kvôli jednoduchosti používame java.util.Map simulovať databázu:

súkromné ​​poverenia mapy = nové HashMap (); súkromná mapa role = new HashMap (); súkromná mapa perm = nový HashMap (); {credentials.put ("užívateľ", "heslo"); credentials.put ("užívateľ2", "heslo2"); credentials.put ("user3", "password3"); role.put ("pouzivatel", nova HashSet (Arrays.asList ("admin"))); role.put ("user2", nový HashSet (Arrays.asList ("editor"))); role.put ("user3", nový HashSet (Arrays.asList ("autor"))); perm.put ("admin", nový HashSet (Arrays.asList ("*"))); perm.put ("editor", nový HashSet (Arrays.asList ("articles: *"))); perm.put ("autor", nový HashSet (Arrays.asList ("articles: compose", "articles: save"))); }

Poďme pokračovať a prekonať doGetAuthenticationInfo ():

chránený AuthenticationInfo doGetAuthenticationInfo (token AuthenticationToken) hodí AuthenticationException {UsernamePasswordToken uToken = (UsernamePasswordToken) token; if (uToken.getUsername () == null || uToken.getUsername (). isEmpty () ||! credentials.containsKey (uToken.getUsername ())) {throw new UnknownAccountException ("username not found!"); } vrátiť nové SimpleAuthenticationInfo (uToken.getUsername (), credentials.get (uToken.getUsername ()), getName ()); }

Najskôr sme nahodili AuthenticationToken poskytované UsernamePasswordToken. Z uToken, extrahujeme meno používateľa (uToken.getUsername ()) a použite ho na získanie prihlasovacích údajov používateľa (hesla) z databázy.

Ak sa nenájde žiadny záznam - hodíme UnknownAccountException, inak použijeme prihlasovacie údaje a používateľské meno na vytvorenie a SimpleAuthenticatioInfo objekt vrátený z metódy.

Ak je poverenie používateľa zahašované soľou, musíme vrátiť a SimpleAuthenticationInfo s pridanou soľou:

vrátiť nové SimpleAuthenticationInfo (uToken.getUsername (), credentials.get (uToken.getUsername ()), ByteSource.Util.bytes ("soľ"), getName ());

Musíme tiež prekonať doGetAuthorizationInfo (), ako aj getRoleNamesForUser () a getPermissions ().

Na záver pripojíme vlastnú sféru do securityManager. Všetko, čo musíme urobiť, je vymeniť IniRealm vyššie s našou vlastnou sférou a odovzdať ju DefaultSecurityManagerKonštruktér:

Realm realm = new MyCustomRealm (); SecurityManager securityManager = nový DefaultSecurityManager (realm);

Každá ďalšia časť kódu je rovnaká ako predtým. To je všetko, čo musíme nakonfigurovať securityManager s vlastnou ríšou správne.

Teraz je namieste otázka - ako sa rámec zhoduje s povereniami?

V predvolenom nastavení je JdbcRealm používa SimpleCredentialsMatcher, ktorý iba kontroluje rovnosť porovnaním údajov v AuthenticationToken a AuthenticationInfo.

Ak máme hašované heslá, musíme informovať rámec, aby mohol používať a HashedCredentialsMatcher namiesto toho. Konfigurácie INI pre sféry s hašovanými heslami nájdete tu.

7. Odhlásenie

Teraz, keď sme overili používateľa, je čas implementovať odhlásenie. To sa deje jednoducho volaním jednej metódy - ktorá zneplatní reláciu používateľa a odhlási používateľa:

currentUser.logout ();

8. Riadenie relácie

Rámec prirodzene prichádza so svojím systémom riadenia relácií. Ak sa používa vo webovom prostredí, použije sa predvolene HttpSession implementácia.

Pre samostatnú aplikáciu používa svoj systém správy podnikových relácií. Výhodou je, že aj v desktopovom prostredí môžete použiť objekt relácie ako v bežnom webovom prostredí.

Pozrime sa na krátky príklad a interagujeme s reláciou aktuálneho používateľa:

Relácia session = currentUser.getSession (); session.setAttribute ("kľúč", "hodnota"); String value = (String) session.getAttribute ("kľúč"); if (value.equals ("value")) {log.info ("Získal správnu hodnotu! [" + hodnota + "]"); }

9. Shiro pre webovú aplikáciu s jarou

Doteraz sme načrtli základnú štruktúru Apache Shiro a implementovali sme ju do desktopového prostredia. Pokračujme integráciou rámca do aplikácie Spring Boot.

Všimnite si, že hlavným zameraním je tu Shiro, nie jarná aplikácia - tú použijeme iba na napájanie jednoduchej ukážkovej aplikácie.

9.1. Závislosti

Najskôr musíme do našej pridať závislosť rodičov Spring Boot pom.xml:

 org.springframework.boot spring-boot-starter-parent 2.2.6.RELEASE 

Ďalej musíme do rovnakej pridať nasledujúce závislosti pom.xml spis:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-freemarker org.apache.shiro shiro-spring-boot-web-starter $ {apache-shiro-core-verzia} 

9.2. Konfigurácia

Pridáva sa štartér shiro-spring-boot-web závislosť na našom pom.xml predvolene nakonfiguruje niektoré funkcie aplikácie Apache Shiro, ako napríklad SecurityManager.

Stále však musíme nakonfigurovať Ríša a Shiro bezpečnostné filtre. Budeme používať rovnakú vlastnú sféru definovanú vyššie.

A tak k hlavnej triede, kde je spustená aplikácia Spring Boot, pridajme nasledujúce Bean definície:

@Bean public Realm realm () {return new MyCustomRealm (); } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition () {DefaultShiroFilterChainDefinition filter = nový DefaultShiroFilterChainDefinition (); filter.addPathDefinition ("/ secure", "authc"); filter.addPathDefinition ("/ **", "anon"); spätný filter; }

V Definícia reťazca ShiroFilterChain, aplikovali sme authc filtrovať do /zabezpečiť cesta a aplikoval anon filtrovať na iných cestách pomocou vzoru Ant.

Oboje authc a anon filtre sa predvolene dodávajú pre webové aplikácie. Ďalšie predvolené filtre nájdete tu.

Keby sme nedefinovali Ríša fazuľa, ShiroAutoConfiguration štandardne poskytne IniRealm implementácia, ktorá očakáva nájdenie a shiro.ini uložiť v src / main / resources alebo src / main / resources / META-INF.

Ak nedefinujeme a Definícia reťazca ShiroFilterChain fazuľa, rámec zabezpečí všetky cesty a nastaví prihlasovaciu URL ako login.jsp.

Túto predvolenú prihlasovaciu adresu URL a ďalšie predvolené nastavenia môžeme zmeniť pridaním nasledujúcich záznamov do našej adresy application.properties:

shiro.loginUrl = / prihlásenie shiro.successUrl = / bezpečné shiro.unauthorizedUrl = / prihlásenie

Teraz, keď authc filter bol aplikovaný na /zabezpečiť, všetky požiadavky na túto trasu budú vyžadovať overenie formulára.

9.3. Autentifikácia a autorizácia

Vytvorme a ShiroSpringController s nasledujúcimi mapovaniami ciest: / index, / prihlásenie, / odhlásenie a /zabezpečiť.

The Prihlásiť sa() Táto metóda implementuje skutočné overenie používateľa, ako je opísané vyššie. Ak je overenie úspešné, používateľ je presmerovaný na zabezpečenú stránku:

Predmet predmetu = SecurityUtils.getSubject (); if (! subject.isAuthenticated ()) {UsernamePasswordToken token = nový UsernamePasswordToken (cred.getUsername (), cred.getPassword (), cred.isRememberMe ()); skúsiť {subject.login (token); } catch (AuthenticationException ae) {ae.printStackTrace (); attr.addFlashAttribute ("chyba", "neplatné poverenia"); návrat "redirect: / login"; }} return "redirect: / secure";

A teraz v zabezpečiť() implementácia, súčasný užívateľ bol získaný vyvolaním SecurityUtils.getSubject (). Rola a povolenia používateľa sa prenášajú na zabezpečenú stránku, ako aj principál používateľa:

Predmet currentUser = SecurityUtils.getSubject (); Reťazec role = "", povolenie = ""; if (currentUser.hasRole ("admin")) {role = role + "Ste správca"; } else if (currentUser.hasRole ("editor")) {role = role + "Ste redaktor"; } else if (currentUser.hasRole ("autor")) {role = role + "Ste autorom"; } if (currentUser.isPermitted ("articles: compose")) {povolenie = povolenie + "Môžete vytvoriť článok,"; } else {povolenie = povolenie + "Nemáte oprávnenie vytvárať článok !,"; } if (currentUser.isPermitted ("articles: save")) {povolenie = povolenie + "Môžete ukladať články,"; } else {povolenie = povolenie + "\ nČlánky nemôžete ukladať,"; } if (currentUser.isPermitted ("articles: publish")) {povolenie = povolenie + "\ nMôžete publikovať články"; } else {povolenie = povolenie + "\ nČlánky nemôžete publikovať"; } modelMap.addAttribute ("používateľské meno", currentUser.getPrincipal ()); modelMap.addAttribute ("povolenie", povolenie); modelMap.addAttribute ("role", role); návrat "bezpečný";

A sme hotoví. Takto môžeme integrovať Apache Shiro do aplikácie Spring Boot.

Upozorňujeme tiež, že rámec ponúka ďalšie anotácie, ktoré je možné použiť spolu s definíciami filtračných reťazcov na zabezpečenie našej aplikácie.

10. Integrácia JEE

Integrácia Apache Shiro do aplikácie JEE je len otázkou konfigurácie web.xml spis. Ako obvykle, konfigurácia očakáva shiro.ini byť v triede. Podrobná ukážka konfigurácie je k dispozícii tu. Značky JSP tiež nájdete tu.

11. Záver

V tomto tutoriáli sme sa pozreli na mechanizmy autentifikácie a autorizácie Apache Shiro. Zamerali sme sa tiež na to, ako definovať vlastnú sféru a zapojiť ju do SecurityManager.

Celý zdrojový kód je ako vždy k dispozícii na stránkach GitHub.