Spring Cloud - zabezpečovacie služby

1. Prehľad

V predchádzajúcom článku, Spring Cloud - Bootstrapping, sme vytvorili základné Jarný mrak žiadosť. Tento článok ukazuje, ako to zabezpečiť.

Prirodzene použijeme Jarná bezpečnosť zdieľať relácie pomocou Jarné zasadnutie a Redis. Táto metóda je ľahko nastaviteľná a dá sa ľahko rozšíriť do mnohých obchodných scenárov. Ak vám nie sú známe Jarné zasadnutie, pozrite sa na tento článok.

Zdieľanie relácií nám dáva možnosť prihlásiť používateľov do našej služby brány a šíriť túto autentifikáciu do akejkoľvek inej služby nášho systému.

Ak vám nie sú známe Redis aleboJarná bezpečnosť, je dobré si v tomto okamihu rýchlo prečítať tieto témy. Aj keď je veľká časť článku pripravená na kopírovanie a vkladanie pre aplikáciu, neexistuje žiadna náhrada za pochopenie toho, čo sa deje pod kapotou.

Na úvod do Redis prečítajte si tento návod. Na úvod do Jarná bezpečnosť čítať jarné zabezpečené prihlásenie, rola a privilégium pre jarnú zabezpečenú registráciu a jarné zabezpečené sedenie. Ak chcete úplne porozumieť Jarná bezpečnosť, pozrite sa na triedu learn-spring-security-the-master.

2. Nastavenie Maven

Začnime tým, že ku každému modulu v systéme pridáme závislosť bezpečnosti jar-boot-štartér-bezpečnosť:

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

Pretože používame Jar správu závislostí môžeme verzie vynechať štartér s pružinou závislosti.

Ako druhý krok upravme pom.xml každej aplikácie so závislosťami spring-session, spring-boot-starter-data-redis:

 org.springframework.session jarná relácia org.springframework.boot spring-boot-starter-data-redis 

Iba štyri z našich aplikácií sa spoja Jarné zasadnutie: objav, brána, knižná službaa hodnotiaca služba.

Ďalej pridajte triedu konfigurácie relácie do všetkých troch služieb v rovnakom adresári ako hlavný súbor aplikácie:

Verejná trieda @EnableRedisHttpSession SessionConfig rozširuje AbstractHttpSessionApplicationInitializer {}

Na záver pridajte tieto vlastnosti k týmto trom * .vlastnosti súbory v našom úložisku git:

spring.redis.host = localhost spring.redis.port = 6379

Teraz prejdime k konfigurácii konkrétnej služby.

3. Zabezpečenie služby Config

Konfiguračná služba obsahuje citlivé informácie, ktoré často súvisia s databázovými pripojeniami a kľúčmi API. Tieto informácie nemôžeme kompromitovať, takže sa na to ponorme a zabezpečme túto službu.

Pridajme do zabezpečenia vlastnosti zabezpečenia application.properties uložiť v src / main / resources konfiguračnej služby:

eureka.client.serviceUrl.defaultZone = // discUser: [chránený e-mailom]: 8082 / eureka / security.user.name = configUser security.user.password = configPassword security.user.role = SYSTÉM

Týmto nastavíme našu službu na prihlásenie s objavením. Okrem toho konfigurujeme našu bezpečnosť pomocou application.properties spis.

Poďme si teraz nakonfigurovať našu vyhľadávaciu službu.

4. Zabezpečenie vyhľadávacej služby

Naša objavná služba obsahuje citlivé informácie o umiestnení všetkých služieb v aplikácii. Registruje tiež nové inštancie týchto služieb.

Ak klienti so zlým úmyslom získajú prístup, naučia sa sieťové umiestnenie všetkých služieb v našom systéme a budú môcť zaregistrovať svoje vlastné škodlivé služby do našej aplikácie. Je veľmi dôležité, aby bola služba objavovania zabezpečená.

4.1. Konfigurácia zabezpečenia

Pridajme bezpečnostný filter na ochranu koncových bodov, ktoré budú používať ďalšie služby:

@Configuration @EnableWebSecurity @Order (1) verejná trieda SecurityConfig rozširuje WebSecurityConfigurerAdapter {@Autowired public void configureGlobal (AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication (). WithUser ("discUser") .password ("diskPassword" "diskPassword" "diskPassword" " ); } @Override protected void configure (HttpSecurity http) {http.sessionManagement () .sessionCreationPolicy (SessionCreationPolicy.ALWAYS) .and (). RequestMatchers (). AntMatchers ("/ eureka / **") .and (). AuthorizeRequests () .antMatchers ("/ eureka / **") .hasRole ("SYSTÉM"). anyRequest (). denyAll (). a () .httpBasic (). a (). csrf (). disable (); }}

Týmto sa nastaví naša služba s ‘SYSTÉM„Užívateľ. Toto je základné Jarná bezpečnosť konfigurácia s niekoľkými zvratmi. Poďme sa pozrieť na tieto zvraty:

  • @Objednávka (1) - povie Jar najskôr zapojiť tento bezpečnostný filter tak, aby bol vykonaný pokus pred ostatnými
  • .sessionCreationPolicy - povie Jar vždy vytvoriť reláciu, keď sa používateľ prihlási pomocou tohto filtra
  • .requestMatchers - obmedzuje, na ktoré koncové body sa tento filter vzťahuje

Bezpečnostný filter, ktorý sme práve nastavili, konfiguruje izolované autentifikačné prostredie, ktoré sa týka iba vyhľadávacej služby.

4.2. Zabezpečenie palubnej dosky Eureka

Pretože naša objavovacia aplikácia má pekné používateľské rozhranie na prezeranie aktuálne registrovaných služieb, vystavme to pomocou druhého bezpečnostného filtra a spojme tento s autentifikáciou zvyšku našej aplikácie. Majte na pamäti, že nie @Objednať() značka znamená, že toto je posledný bezpečnostný filter, ktorý sa má vyhodnotiť:

@Configuration verejná statická trieda AdminSecurityConfig rozširuje WebSecurityConfigurerAdapter {@Override chránený neplatný konfigurovať (HttpSecurity http) {http.sessionManagement (). SessionCreationPolicy (SessionCreationPolicy.NEVER). A (). HttpBasic (). Disable (). AuthorizeRequests HttpMethod.GET, "/" ).hasRole("ADMIN") .antMatchers ("/ info", "/ health"). Autentified (). AnyRequest () .denyAll (). A (). Csrf (). Deaktivovať (); }}

Pridajte túto konfiguračnú triedu do súboru SecurityConfig trieda. Takto sa vytvorí druhý bezpečnostný filter, ktorý bude riadiť prístup do nášho používateľského rozhrania. Tento filter má niekoľko neobvyklých vlastností, pozrime sa na tie:

  • httpBasic (). disable () - informuje zabezpečenie pružiny, aby deaktivovala všetky postupy overovania tohto filtra
  • sessionCreationPolicy - nastavili sme to NIKDY označujeme, že požadujeme, aby sa používateľ už pred prístupom k zdrojom chráneným týmto filtrom overil

Tento filter nikdy nenastaví reláciu používateľa a spolieha sa na Redis na vyplnenie zdieľaného bezpečnostného kontextu. Z tohto dôvodu závisí od poskytovania autentifikácie iná služba, brána.

4.3. Autentifikácia pomocou služby Config

V projekte objavu pripojme k vlastnosti dve vlastnosti bootstrap.properties v src / main / resources:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword

Tieto vlastnosti umožnia overovacej službe autentifikáciu u konfiguračnej služby pri štarte.

Aktualizujme naše objav.vlastnosti v našom úložisku Git

eureka.client.serviceUrl.defaultZone = // discUser: [chránený e-mailom]: 8082 / eureka / eureka.client.register-with-eureka = false eureka.client.fetch-registry = false

Do našich služieb sme pridali základné autentifikačné údaje objav služba, ktorá mu umožňuje komunikovať s konfigur služby. Dodatočne konfigurujeme Heuréka spustiť v samostatnom režime a povedať našej službe, aby sa neregistrovala sama so sebou.

Poďme súbor odovzdať git Úložisko. V opačnom prípade nebudú zmeny zistené.

5. Zabezpečenie služby brány

Naša služba brány je jedinou časťou našej aplikácie, ktorú chceme vystaviť svetu. Preto bude potrebovať zabezpečenie, ktoré zabezpečí, aby k citlivým informáciám mali prístup iba autentifikovaní používatelia.

5.1. Konfigurácia zabezpečenia

Vytvorme a SecurityConfig triedy ako naša objavná služba a prepíšeme metódy týmto obsahom:

@Autowired public void configureGlobal (AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication (). WithUser ("užívateľ"). Heslo ("heslo") .roles ("USER"). A (). WithUser ("admin"). Heslo ( „admin“) .roles („ADMIN“); } @Override protected void configure (HttpSecurity http) {http.authorizeRequests (). AntMatchers ("/ book-service / books") .permitAll (). AntMatchers ("/ eureka / **"). HasRole ("ADMIN") .anyRequest (). authenticated (). a (). formLogin (). a () .logout (). permitAll (). logoutSuccessUrl ("/ book-service / books") .permitAll (). a () .srf (). deaktivovať (); }

Táto konfigurácia je celkom jednoduchá. Deklarujeme bezpečnostný filter s prihlásením do formulára, ktorý zaisťuje rôzne koncové body.

Zabezpečenie na / eureka / ** slúži na ochranu niektorých statických zdrojov, ktoré budeme slúžiť z našej služby brány pre server Heuréka stavová stránka. Ak staviate projekt pomocou článku, skopírujte zdroj / statický priečinok z projektu brány na Github do vášho projektu.

Teraz upravíme @EnableRedisHttpSession anotácia k našej konfiguračnej triede:

@EnableRedisHttpSession (redisFlushMode = RedisFlushMode.IMMEDIATE)

Nastavili sme režim vyprázdňovania na okamžité, aby sme okamžite udržali akékoľvek zmeny v relácii. To pomáha pri príprave autentifikačného tokenu na presmerovanie.

Na záver pridajme a ZuulFilter ktorý po prihlásení pošle náš autentifikačný token:

@Component public class SessionSavingZuulPreFilter rozširuje ZuulFilter {@Autowired súkromné ​​úložisko SessionRepository; @Override public boolean shouldFilter () {return true; } @Override public Object run () {RequestContext context = RequestContext.getCurrentContext (); HttpSession httpSession = context.getRequest (). GetSession (); Relácia session = repository.getSession (httpSession.getId ()); context.addZuulRequestHeader ("Cookie", "SESSION =" + httpSession.getId ()); návrat null; } @Override public String filterType () {return "pre"; } @Override public int filterOrder () {návrat 0; }}

Tento filter uchopí požiadavku, pretože je po prihlásení presmerovaná, a do hlavičky pridá kľúč relácie ako súbor cookie. Týmto sa po prihlásení rozšíri autentifikácia na akúkoľvek podpornú službu.

5.2. Autentifikácia pomocou služby Config and Discovery Service

Pridajme nasledujúce vlastnosti autentifikácie do bootstrap.properties uložiť v src / main / resources služby brány:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword eureka.client.serviceUrl.defaultZone = // discUser: [chránený e-mailom]: 8082 / eureka /

Ďalej aktualizujme naše brána.vlastnosti v našom úložisku Git

management.security.sessions = always zuul.routes.book-service.path = / book-service / ** zuul.routes.book-service.sensitive-headers = Set-Cookie, autorizácia hystrix.command.book-service.execution .isolation.thread .timeoutInMilliseconds = 600 000 zuul.routes.rating-service.path = / rating-service / ** zuul.routes.rating-service.sensitive-headers = Set-Cookie, autorizácia hystrix.command.rating-service. execution.isolation.thread .timeoutInMilliseconds = 600000 zuul.routes.discovery.path = / discovery / ** zuul.routes.discovery.sensitive-headers = Set-Cookie, autorizácia zuul.routes.discovery.url = // localhost: 8082 hystrix.command.discovery.execution.isolation.thread .timeoutInMilliseconds = 600000

Pridali sme správu relácií, aby sa relácie vždy generovali, pretože máme iba jeden bezpečnostný filter, ktorý môžeme nastaviť v súbore vlastností. Ďalej pridáme naše Redis vlastnosti hostiteľa a servera.

Okrem toho sme pridali cestu, ktorá presmeruje požiadavky na našu vyhľadávaciu službu. Pretože sa samostatná služba objavovania nebude sama registrovať, musíme ju vyhľadať pomocou schémy URL.

Môžeme odstrániť serviceUrl.defaultZone majetok z brána.vlastnosti súbor v našom konfiguračnom úložisku git. Táto hodnota je duplikovaná v bootstrap spis.

Odovzdajme súbor do úložiska Git, inak nebudú zmeny zistené.

6. Zabezpečenie knižnej služby

Server knižných služieb bude obsahovať citlivé informácie riadené rôznymi používateľmi. Táto služba musí byť zabezpečená, aby sa zabránilo úniku chránených informácií v našom systéme.

6.1. Konfigurácia zabezpečenia

Na zabezpečenie našej knižnej služby skopírujeme SecurityConfig triedy z brány a metódu prepíšete týmto obsahom:

@Override protected void configure (HttpSecurity http) {http.httpBasic (). Disable (). AuthorizeRequests () .antMatchers ("/ books"). PermitAll () .antMatchers ("/ books / *"). HasAnyRole ("USER" "," ADMIN ") .authenticated (). A (). Csrf (). Disable (); }

6.2. Vlastnosti

Pridajte tieto vlastnosti do bootstrap.properties uložiť v src / main / resources knižnej služby:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword eureka.client.serviceUrl.defaultZone = // discUser: [chránený e-mailom]: 8082 / eureka /

Pridajme vlastnosti k nášmu book-service.properties súbor v našom úložisku git:

management.security.sessions = nikdy

Môžeme odstrániť serviceUrl.defaultZone majetok z book-service.properties súbor v našom konfiguračnom úložisku git. Táto hodnota je duplikovaná v bootstrap spis.

Nezabudnite vykonať tieto zmeny, aby ich knižná služba vyzdvihla.

7. Zabezpečenie hodnotiacej služby

Je tiež potrebné zabezpečiť ratingovú službu.

7.1. Konfigurácia zabezpečenia

Na zabezpečenie našej hodnotiacej služby skopírujeme SecurityConfig triedy z brány a metódu prepíšete týmto obsahom:

@Override protected void configure (HttpSecurity http) {http.httpBasic (). Disable (). AuthorizeRequests () .antMatchers ("/ hodnotenie"). HasRole ("USER") .antMatchers ("/ hodnotenie / všetko"). HasAnyRole ("USER", "ADMIN"). AnyRequest () .authenticated (). A (). Csrf (). Disable (); }

Môžeme vymazať configureGlobal () metóda z brána služby.

7.2. Vlastnosti

Pridajte tieto vlastnosti do bootstrap.properties uložiť v src / main / resources hodnotiacej služby:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword eureka.client.serviceUrl.defaultZone = // discUser: [chránený e-mailom]: 8082 / eureka /

Pridajme vlastnosti do našej hodnotiacej služby.vlastnosti súbor v našom úložisku git:

management.security.sessions = nikdy

Môžeme odstrániť serviceUrl.defaultZone majetok z ratingovej služby.vlastnosti súbor v našom konfiguračnom úložisku git. Táto hodnota je duplikovaná v bootstrap spis.

Nezabudnite vykonať tieto zmeny, aby ich hodnotiaca služba vyzdvihla.

8. Beh a testovanie

Štart Redis a všetky služby pre aplikáciu: konfigurácia, objav, brána, knižná služba, a hodnotiaca služba. Teraz poďme otestovať!

Najskôr si vytvorme testovaciu triedu v našom brána projekt a vytvoriť metódu pre náš test:

verejná trieda GatewayApplicationLiveTest {@Test verejné neplatné testAccess () {...}}

Ďalej nastavíme náš test a overíme, či máme prístup k našim nechráneným / knižná služba / knihy zdroj pridaním tohto útržku kódu do našej testovacej metódy:

TestRestTemplate testRestTemplate = nový TestRestTemplate (); Reťazec testUrl = "// localhost: 8080"; ResponseEntity response = testRestTemplate .getForEntity (testUrl + "/ book-service / books", String.class); Assert.assertEquals (HttpStatus.OK, response.getStatusCode ()); Assert.assertNotNull (response.getBody ());

Spustite tento test a overte výsledky. Ak uvidíme zlyhania, potvrďte, že sa celá aplikácia úspešne spustila a konfigurácie sa načítali z nášho konfiguračného úložiska git.

Teraz otestujme, že naši používatelia budú presmerovaní na prihlásenie, keď navštívime chránený prostriedok ako neautentizovaný používateľ, pripojením tohto kódu na koniec testovacej metódy:

response = testRestTemplate .getForEntity (testUrl + "/ book-service / books / 1", String.class); Assert.assertEquals (HttpStatus.FOUND, response.getStatusCode ()); Assert.assertEquals ("// localhost: 8080 / login", response.getHeaders () .get ("Umiestnenie"). Get (0));

Spustite test znova a potvrďte, že bol úspešný.

Ďalej sa skutočne prihlásime a potom použijeme našu reláciu na prístup k výsledku chránenému používateľom:

Formulár MultiValueMap = nový LinkedMultiValueMap (); form.add ("používateľské meno", "užívateľ"); form.add ("heslo", "heslo"); response = testRestTemplate .postForEntity (testUrl + "/ login", form, String.class); 

Poďme teraz extrahovať reláciu z cookie a rozšíriť ju na nasledujúcu požiadavku:

Reťazec sessionCookie = response.getHeaders (). Get ("Set-Cookie") .get (0) .split (";") [0]; Hlavičky HttpHeaders = nové HttpHeaders (); headers.add ("Cookie", sessionCookie); HttpEntity httpEntity = nový HttpEntity (hlavičky); 

a požiadať o chránený zdroj:

response = testRestTemplate.exchange (testUrl + "/ book-service / books / 1", HttpMethod.GET, httpEntity, String.class); Assert.assertEquals (HttpStatus.OK, response.getStatusCode ()); Assert.assertNotNull (response.getBody ());

Znova spustite test, aby ste potvrdili výsledky.

Teraz sa pokúsime dostať do sekcie správcu s rovnakou reláciou:

response = testRestTemplate.exchange (testUrl + "/ rating-service / Ratings / all", HttpMethod.GET, httpEntity, String.class); Assert.assertEquals (HttpStatus.FORBIDDEN, response.getStatusCode ());

Spustite test znova a podľa očakávania máme obmedzený prístup do správcovských oblastí ako obyčajný starý používateľ.

Nasledujúci test potvrdí, že sa môžeme prihlásiť ako správca a získať prístup k prostriedku chránenému správcom:

form.clear (); form.add ("používateľské meno", "admin"); form.add ("heslo", "admin"); response = testRestTemplate .postForEntity (testUrl + "/ login", form, String.class); sessionCookie = response.getHeaders (). get ("Set-Cookie"). get (0) .split (";") [0]; hlavičky = nové HttpHeaders (); headers.add ("Cookie", sessionCookie); httpEntity = nový HttpEntity (hlavičky); response = testRestTemplate.exchange (testUrl + "/ rating-service / Ratings / all", HttpMethod.GET, httpEntity, String.class); Assert.assertEquals (HttpStatus.OK, response.getStatusCode ()); Assert.assertNotNull (response.getBody ());

Náš test sa zväčšuje! Ale keď to spustíme, môžeme vidieť, že prihlásením sa ako správca získame prístup k prostriedku správcu.

Náš posledný test je prístup k nášmu vyhľadávaciemu serveru prostredníctvom našej brány. Za týmto účelom pridajte tento kód na koniec nášho testu:

response = testRestTemplate.exchange (testUrl + "/ discovery", HttpMethod.GET, httpEntity, String.class); Assert.assertEquals (HttpStatus.OK, response.getStatusCode ());

Spustite tento test naposledy, aby ste sa ubezpečili, že všetko funguje. Úspech!!!

To ti chýbalo? Pretože sme sa prihlásili do našej služby brány a prezerali sme si obsah našich knižných, hodnotiacich a objavovacích služieb bez toho, aby sme sa museli prihlásiť na štyroch samostatných serveroch!

Využitím Jarné zasadnutie na šírenie nášho autentifikačného objektu medzi servermi sme schopní sa raz prihlásiť na bráne a použiť túto autentifikáciu na prístup k radičom na ľubovoľnom počte podporných služieb.

9. Záver

Bezpečnosť v cloude sa určite komplikuje. Ale s pomocou Jarná bezpečnosť a Jarné zasadnutie, môžeme tento kritický problém ľahko vyriešiť.

Teraz máme okolo našich služieb cloudovú aplikáciu so zabezpečením. Použitím Zuul a Jarné zasadnutie môžeme používateľov prihlásiť iba do jednej služby a rozšíriť toto overenie na celú našu aplikáciu. To znamená, že môžeme našu aplikáciu ľahko rozdeliť do správnych domén a zabezpečiť každú z nich, ako uznáme za vhodné.

Ako vždy nájdete zdrojový kód na GitHub.


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