Tavaszi Biztonság vs Apache Shiro

1. Áttekintés

Az alkalmazásfejlesztés világában elsődleges szempont a biztonság, különösen a vállalati webes és mobil alkalmazások területén.

Ebben a gyors bemutatóban összehasonlítunk két népszerű Java Security keretrendszert - az Apache Shiro és a Spring Security programokat.

2. Egy kis háttér

Apache Shiro 2004-ben született JSecurity néven, és az Apache Alapítvány 2008-ban fogadta el. A mai napig sok kiadást látott, a legújabb íráskor ez 1.5.3.

A Spring Security 2003-ban Acegi néven indult, és az első nyilvános kiadásával, 2008-ban beépült a Spring Framework-be. Megalakulása óta számos ismétlést hajtott végre, és a GA jelenlegi verziója az íráskor ez az 5.3.2.

Mindkét technológia kínál hitelesítési és hitelesítési támogatás, valamint kriptográfia és munkamenet-kezelési megoldások. Ezenkívül a Spring Security első osztályú védelmet nyújt olyan támadások ellen, mint a CSRF és a munkamenet rögzítése.

A következő néhány szakaszban példákat láthatunk arra, hogyan kezeli a két technológia a hitelesítést és az engedélyezést. A dolgok egyszerűségének megőrzése érdekében alap SpringWoot alapú MVC alkalmazásokat fogunk használni FreeMarker sablonokkal.

3. Az Apache Shiro konfigurálása

Először nézzük meg, hogy a konfigurációk hogyan különböznek a két keretrendszer között.

3.1. Maven-függőségek

Mivel a Shirót egy Spring Boot alkalmazásban fogjuk használni, szükségünk lesz az indítójára és a shiro-mag modul:

 org.apache.shiro shiro-spring-boot-web-starter 1.5.3 org.apache.shiro shiro-core 1.5.3 

A legújabb verziók a Maven Central oldalon találhatók.

3.2. Birodalom létrehozása

Ahhoz, hogy a felhasználókat memóriájába nyilvánítsuk szerepeikkel és engedélyeikkel, létre kell hoznunk egy birodalmat, amely kiterjeszti a Shiro-t JdbcRealm. Két felhasználót fogunk meghatározni - Tom és Jerry, a USER és az ADMIN szerepekkel:

public class A CustomRealm kiterjeszti a JdbcRealm {private Map hitelesítő adatokat = új HashMap (); privát térkép szerepek = new HashMap (); privát térkép engedélyek = új HashMap (); {credentials.put ("Tom", "jelszó"); credentials.put ("Jerry", "jelszó"); szerepek.put ("Jerry", új HashSet (tömbök.Lista ("ADMIN"))); role.put ("Tom", új HashSet (Arrays.asList ("USER"))); permissions.put ("ADMIN", új HashSet (Arrays.asList ("READ", "WRITE"))); permissions.put ("USER", új HashSet (Arrays.asList ("READ"))); }}

Ezután a hitelesítés és az engedélyezés visszakeresésének engedélyezéséhez felül kell írnunk néhány módszert:

A @Orride védett AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken token) dobja az AuthenticationException {UsernamePasswordToken userToken = (UsernamePasswordToken) tokent; if (userToken.getUsername () == null || userToken.getUsername (). isEmpty () ||! credentials.containsKey (userToken.getUsername ())) {dob új UnknownAccountException ("Felhasználó nem létezik"); } return new SimpleAuthenticationInfo (userToken.getUsername (), credentials.get (userToken.getUsername ()), getName ()); } @Orride védett AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection megbízók) {Set szerepek = new HashSet (); Engedélyek beállítása = new HashSet (); for (Object user: principals) {try {szerepek.addAll (getRoleNamesForUser (null, (String) felhasználó)); permissions.addAll (getPermissions (null, null, szerepkörök)); } catch (SQLException e) {logger.error (e.getMessage ()); }} SimpleAuthorizationInfo authInfo = új SimpleAuthorizationInfo (szerepkörök); authInfo.setStringPermissions (engedélyek); return authInfo; } 

A módszer, a metódus doGetAuthorizationInfo néhány segítő módszert használ a felhasználó szerepeinek és engedélyeinek megszerzéséhez:

@Orride védett A getRoleNamesForUser (Csatlakozási kapcsolat, String felhasználónév) készlet megadta az SQLException parancsot {if (! Role.containsKey (felhasználónév)) {dob új SQLException-t ("A felhasználó nem létezik"); } return szerepek.get (felhasználónév); } @Orride védett A getPermissions beállítása (Connection Conn, String felhasználónév, Gyűjteményi szerepkörök) dobja az SQLException {Set userPermissions = new HashSet (); for (String role: szerepek) {if (! permissions.containsKey (role)) {dobjon új SQLException-t ("A szerep nem létezik"); } userPermissions.addAll (permissions.get (szerepkör)); } return userPermissions; } 

Ezt követően ezt be kell építenünk CustomRealm babként a Boot alkalmazásunkban:

@Bean public Realm customRealm () {return new CustomRealm (); }

Ezenkívül a végpontjaink hitelesítésének konfigurálásához szükségünk van egy másik babra:

@Bean public ShiroFilterChainDefinition shiroFilterChainDefinition () {DefaultShiroFilterChainDefinition filter = new DefaultShiroFilterChainDefinition (); filter.addPathDefinition ("/ home", "authc"); filter.addPathDefinition ("/ **", "anon"); visszatérő szűrő; }

Itt a DefaultShiroFilterChainDefinition például megadtuk, hogy a /itthon a végpontot csak hitelesített felhasználók érhetik el.

Ennyi kell a konfigurációhoz, Shiro a többit elvégzi helyettünk.

4. A tavaszi biztonság beállítása

Most nézzük meg, hogyan lehet elérni ugyanezt tavasszal.

4.1. Maven-függőségek

Először is, a függőségek:

 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security 

A legújabb verziók a Maven Central oldalon találhatók.

4.2. Konfigurációs osztály

Ezután meghatározzuk a Spring Security konfigurációnkat egy osztályban SecurityConfig, kiterjesztve WebSecurityConfigurerAdapter:

Az @EnableWebSecurity nyilvános osztály, a SecurityConfig kiterjeszti a WebSecurityConfigurerAdapter {@Orride protected void configure (HttpSecurity http) dobja a {http .authorizeRequests (autorize -> autorize .antMatchers ("/ index", "/ login"). SallAll () /antMatchers (). home "," / logout "). hitelesített () .antMatchers (" / admin / ** "). hasRole (" ADMIN ")) .formLogin (formLogin -> formLogin .loginPage (" / login ") .failureUrl (" /bejelentkezési hiba")); } A @Orride védett void konfiguráció (AuthenticationManagerBuilder .roles ("ADMIN") .and () .withUser ("Tom") .password (passwordEncoder (). encode ("password")) .authorities ("READ") .roles ("USER"); } @Bean public PasswordEncoder passwordEncoder () {return new BCryptPasswordEncoder (); }} 

Mint láthatjuk, építettünk egy AuthenticationManagerBuilder kifogásolja, hogy kijelentse felhasználóinkat szerepeikkel és jogosultságaikkal. Ezenkívül kódoltuk a jelszavakat az a használatával BCryptPasswordEncoder.

A Tavaszi Biztonság is biztosít nekünk HttpBiztonság objektum további konfigurációkhoz. Példaként megengedtük:

  • mindenki hozzáférjen a mi index és Belépés oldalakat
  • csak hitelesített felhasználók adják meg a itthon oldal és Kijelentkezés
  • csak az ADMIN szerepkörrel rendelkező felhasználók férhetnek hozzá a admin oldalakat

Meghatároztuk az űrlap alapú hitelesítés támogatását is, hogy a felhasználókat a Belépés végpont. Abban az esetben, ha a bejelentkezés sikertelen, a felhasználónkat a rendszer átirányítja /bejelentkezési hiba.

5. Vezérlők és végpontok

Most nézzük meg a két alkalmazás webvezérlői leképezéseit. Míg ugyanazokat a végpontokat fogják használni, egyes megvalósítások eltérnek egymástól.

5.1. Végpontok a nézetmegjelenítéshez

A nézetet megjelenítő végpontok esetében a megvalósítások megegyeznek:

@GetMapping ("/") public String index () {return "index"; } @GetMapping ("/ login") public String showLoginPage () {return "login"; } @GetMapping ("/ home") public String getMeHome (Model model) {addUserAttributes (model); hazatérni"; }

Mind a kontroller megvalósításunk, a Shiro, mind a Spring Security visszaadja a index.ftl a root végponton, login.ftl a bejelentkezési végponton, és home.ftl az otthoni végponton.

A módszer meghatározása azonban addUserAttributes a /itthon a végpont különbözik a két vezérlő között. Ez a módszer megvizsgálja a jelenleg bejelentkezett felhasználó attribútumait.

Shiro biztosítja a SecurityUtils # getSubject hogy lekérje az áramot Tantárgy, valamint szerepei és engedélyei:

private void addUserAttributes (Model model) {Subject currentUser = SecurityUtils.getSubject (); Karakterlánc engedély = ""; if (currentUser.hasRole ("ADMIN")) {model.addAttribute ("szerep", "ADMIN"); } else if (currentUser.hasRole ("USER")) {model.addAttribute ("szerep", "USER"); } if (currentUser.isPermitted ("OLVASD")) {engedély = engedély + "OLVAS"; } if (currentUser.isPermitted ("WRITE")) {engedély = engedély + "ÍR"; } model.addAttribute ("felhasználónév", currentUser.getPrincipal ()); model.addAttribute ("engedély", engedély); }

Másrészt a Spring Security biztosítja Hitelesítés objektum annak SecurityContextHolderA kontextus ebből a célból:

private void addUserAttributes (modellmodell) {Hitelesítés auth = SecurityContextHolder.getContext (). getAuthentication (); if (auth! = null &&! auth.getClass (). egyenlő (AnonymousAuthenticationToken.class)) {Felhasználó felhasználó = (Felhasználó) auth.getPrincipal (); model.addAttribute ("felhasználónév", user.getUsername ()); Gyűjtési hatóságok = user.getAuthorities (); for (GrantedAuthority hatóság: hatóságok) {if (hatóság.getAuthority (). tartalmazza ("FELHASZNÁLÓ")) {model.addAttribute ("szerep", "FELHASZNÁLÓ"); model.addAttribute ("engedélyek", "READ"); } else if (Authority.getAuthority (). tartalmazza ("ADMIN")) {model.addAttribute ("role", "ADMIN"); model.addAttribute ("engedélyek", "OLVASSA EL ÍRÁS"); }}}}

5.2. POST bejelentkezési végpont

Shiro-ban feltérképezzük a felhasználó által megadott hitelesítő adatokat egy POJO-hoz:

public class UserCredentials {private String felhasználónév; privát karakterlánc jelszó; // szerelők és beállítók}

Akkor létrehozunk egy FelhasználónévPasswordToken a felhasználó naplózása, vagy Tantárgy, ban ben:

@PostMapping ("/ login") public String doLogin (HttpServletRequest req, UserCredentials hitelesítő adatok, RedirectAttributes attr) {Subject subject = SecurityUtils.getSubject (); if { próbáld ki a {subject.login (token); } catch (AuthenticationException ae) {logger.error (ae.getMessage ()); attr.addFlashAttribute ("hiba", "Érvénytelen hitelesítő adatok"); return "redirect: / login"; }} return "redirect: / home"; }

A tavaszi biztonsági oldalon ez csak a kezdőlapra történő átirányítás kérdése. A tavaszi bejelentkezési folyamat, amelyet az kezel FelhasználónévPasswordAuthenticationFilter, átlátható számunkra:

@PostMapping ("/ login") public String doLogin (HttpServletRequest req) {return "redirect: / home"; }

5.3. Csak rendszergazdai végpont

Most nézzünk meg egy olyan forgatókönyvet, ahol szerepalapú hozzáférést kell végrehajtanunk. Tegyük fel, hogy van egy / admin végpont, amelyhez való hozzáférést csak az ADMIN szerepkör számára szabad engedélyezni.

Nézzük meg, hogyan lehet ezt megtenni Shiro-ban:

@GetMapping ("/ admin") public String adminOnly (ModelMap modelMap) {addUserAttributes (modelMap); Subject currentUser = SecurityUtils.getSubject (); if (currentUser.hasRole ("ADMIN")) {modelMap.addAttribute ("adminContent", "ezt csak az admin láthatja"); } hazatérni"; }

Itt kivontuk a jelenleg bejelentkezett felhasználót, ellenőriztük, hogy rendelkezik-e ADMIN szereppel, és ennek megfelelően adtunk hozzá tartalmat.

A Spring Security programban nincs szükség a szerepkör programozott ellenőrzésére, már meghatároztuk, hogy ki érheti el ezt a végpontot a mi oldalunkon SecurityConfig. Tehát most csak üzleti logika hozzáadásáról van szó:

@GetMapping ("/ admin") public String adminOnly (HttpServletRequest req, Model model) {addUserAttributes (model); model.addAttribute ("adminContent", "ezt csak az admin láthatja"); hazatérni"; }

5.4. Kijelentkezési végpont

Végül valósítsuk meg a kijelentkezési végpontot.

Shiróban egyszerűen hívunk Tárgy # kijelentkezés:

@PostMapping ("/ logout") public String logout () {Subject subject = SecurityUtils.getSubject (); subject.logout (); return "átirányítás: /"; }

Tavaszra még nem definiáltunk leképezést. Ebben az esetben beindul az alapértelmezett kijelentkezési mechanizmusa, amelyet automatikusan alkalmazunk, mióta kiterjesztettük WebSecurityConfigurerAdapter konfigurációnkban.

6. Apache Shiro vs tavaszi biztonság

Most, hogy megvizsgáltuk a megvalósításbeli különbségeket, nézzünk meg néhány más szempontot.

A közösségi támogatás szempontjából a A Spring Framework általában hatalmas fejlesztői közösséggel rendelkezik, aktívan részt vesz annak fejlesztésében és felhasználásában. Mivel a Spring Security az esernyő része, ugyanazokkal az előnyökkel kell rendelkeznie. Shiro, bár népszerű, nem rendelkezik ilyen alázatos támogatással.

Ami a dokumentációt illeti, ismét a Spring a nyerő.

Van azonban egy kis tanulási görbe a Spring Security-hez. Shiro viszont könnyen érthető. Asztali alkalmazásokhoz a konfigurálás a következőn keresztül: shiro.ini annál könnyebb.

De ismét, amint azt a példa-kivonatokban láttuk, A Spring Security nagyszerű munkát végez az üzleti logika és a biztonság megőrzésébenkülönálló és valóban átfogó biztonságként kínálja a biztonságot.

7. Következtetés

Ebben az oktatóanyagban összehasonlítottuk Apache Shirót a Spring Security-vel.

Éppen legeltettük ezeknek a kereteknek a kínálatát, és sok mindent lehet tovább vizsgálni. Van jó néhány alternatíva, mint például a JAAS és az OACC. Ennek ellenére, úgy tűnik, a Spring Security ezen a ponton nyer.

Mint mindig, a forráskód is elérhető a GitHubon.