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.