Proljetni oblak - usluge osiguranja

1. Pregled

U prethodnom članku, Spring Cloud - Bootstrapping, izgradili smo osnovno Proljetni oblak primjena. Ovaj članak pokazuje kako ga osigurati.

Mi ćemo prirodno koristiti Proljetna sigurnost za dijeljenje sesija pomoću Proljetno zasjedanje i Redis. Ovu je metodu jednostavno postaviti i proširiti na mnoge poslovne scenarije. Ako vam nije poznato Proljetno zasjedanje, pogledajte ovaj članak.

Dijeljenje sesija daje nam mogućnost prijavljivanja korisnika u našu pristupničku uslugu i širenje te provjere autentičnosti na bilo koju drugu uslugu našeg sustava.

Ako vam nije poznato Redis odnProljetna sigurnost, u ovom je trenutku dobro napraviti kratki pregled ovih tema. Iako je velik dio članka copy-paste spreman za aplikaciju, nema zamjene za razumijevanje onoga što se događa ispod haube.

Za uvod u Redis pročitajte ovaj vodič. Za uvod u Proljetna sigurnost pročitajte spring-security-login, role-and-privilege-for-spring-security-registration i spring-security-session. Da biste stekli potpuno razumijevanje Proljetna sigurnost, bacite pogled na majstorsku klasu learn-spring-security-the-master.

2. Postavljanje Mavena

Počnimo s dodavanjem ovisnosti spring-boot-starter-security na svaki modul u sustavu:

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

Jer mi koristimo Proljeće upravljanje ovisnostima za koje možemo izostaviti verzije opruga-čizma-starter ovisnosti.

Kao drugi korak, izmijenimo pom.xml svake aplikacije s ovisnostima spring-session, spring-boot-starter-data-redis:

 org.springframework.session proljetna sesija org.springframework.boot spring-boot-starter-data-redis 

Samo će se četiri naše aplikacije povezati Proljetno zasjedanje: otkriće, gateway, knjiga-usluga, i rejting-usluga.

Zatim dodajte klasu konfiguracije sesije u sve tri usluge u istom direktoriju kao i glavna datoteka aplikacije:

@EnableRedisHttpSession javna klasa SessionConfig proširuje AbstractHttpSessionApplicationInitializer {}

Na kraju, dodajte ova svojstva na tri *.Svojstva datoteke u našem git spremištu:

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

Sada ćemo prijeći na konfiguraciju specifičnu za uslugu.

3. Osiguravanje usluge konfiguriranja

Usluga konfiguriranja sadrži osjetljive informacije često povezane s vezama baze podataka i API ključevima. Ne možemo ugroziti ove podatke, zato zaronimo i osigurajmo ovu uslugu.

Dodajmo sigurnosna svojstva primjena.svojstva uloži u src / glavni / resursi usluge konfiguriranja:

eureka.client.serviceUrl.defaultZone = // diskKorisnik: [zaštićen e-poštom]: 8082 / eureka / security.user.name = configUser security.user.password = configPassword security.user.role = SUSTAV

Ovo će postaviti našu uslugu za prijavu s otkrivanjem. Uz to, svoju sigurnost konfiguriramo s primjena.svojstva datoteka.

Konfigurirajmo sada našu uslugu otkrivanja.

4. Osiguravanje usluge otkrivanja

Naša usluga otkrivanja sadrži osjetljive podatke o mjestu svih usluga u aplikaciji. Također registrira nove slučajeve tih usluga.

Ako zlonamjerni klijenti dobiju pristup, naučit će mrežno mjesto svih usluga u našem sustavu i moći će registrirati vlastite zlonamjerne usluge u našu aplikaciju. Ključno je da je usluga otkrivanja osigurana.

4.1. Konfiguracija sigurnosti

Dodajmo sigurnosni filtar da zaštitimo krajnje točke koje će druge usluge koristiti:

@Configuration @EnableWebSecurity @Order (1) javna klasa SecurityConfig proširuje WebSecurityConfigurerAdapter {@Autowired javna prazna konfiguracijaGlobal (AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication (). WithUser ("discUser "Password. ); } @Override zaštićena void konfiguracija (HttpSecurity http) {http.sessionManagement () .sessionCreationPolicy (SessionCreationPolicy.ALWAYS) .and (). RequestMatchers (). AntMatchers ("/ eureka / **"). I (). AuthzeRequests () .antMatchers ("/ eureka / **") .hasRole ("SUSTAV"). anyRequest (). denyAll (). i () .httpBasic (). i (). csrf (). disable (); }}

Ovo će postaviti našu uslugu s 'SUSTAV‘Korisnik. Ovo je osnovno Proljetna sigurnost konfiguracija s nekoliko preokreta. Pogledajmo te preokrete:

  • @Naruči (1) - govori Proljeće prvo spojiti ovaj sigurnosni filtar tako da se pokuša prije bilo kojeg drugog
  • .sessionCreationPolicy - govori Proljeće da uvijek stvori sesiju kada se korisnik prijavi na ovaj filtar
  • .requestMatchers - ograničava na koje se krajnje točke odnosi ovaj filtar

Sigurnosni filtar, koji smo upravo postavili, konfigurira izolirano okruženje za provjeru autentičnosti koje se odnosi samo na uslugu otkrivanja.

4.2. Osiguravanje nadzorne ploče Eureka

Budući da naša aplikacija za otkrivanje ima lijepo korisničko sučelje za pregled trenutno registriranih usluga, izložimo to upotrebom drugog sigurnosnog filtra i povežite ovaj u provjeru autentičnosti za ostatak naše aplikacije. Imajte na umu da br @Narudžba() Oznaka znači da je ovo posljednji sigurnosni filtar koji se procjenjuje:

Javna statička klasa @Configuration AdminSecurityConfig proširuje WebSecurityConfigurerAdapter {@Override zaštićena void konfiguracija (HttpSecurity http) {http.sessionManagement (). SessionCreationPolicy (SessionCreationPolicy.NEVER) .and (). Disable (autorizacija). HttpMethod.GET, "/").hasRole("ADMIN") .antMatchers ("/ info", "/ health"). Authenticated (). AnyRequest () .denyAll (). And (). Csrf (). Disable (); }}

Dodajte ovu klasu konfiguracije u SecurityConfig razred. To će stvoriti drugi sigurnosni filtar koji će kontrolirati pristup našem korisničkom sučelju. Ovaj filtar ima nekoliko neobičnih karakteristika, pogledajmo one:

  • httpBasic (). disable () - govori proljetnoj sigurnosti da onemogući sve postupke provjere autentičnosti za ovaj filtar
  • sessionCreationPolicy - postavili smo ovo na NIKADA kako bismo naznačili da zahtijevamo da je korisnik već ovjeren prije pristupanja resursima zaštićenim ovim filtrom

Ovaj filtar nikada neće postaviti korisničku sesiju i oslanja se na njega Redis za popunjavanje zajedničkog sigurnosnog konteksta. Kao takav, ovisno o drugoj usluzi, pristupniku, koji omogućuje provjeru autentičnosti.

4.3. Autentifikacija pomoću usluge Config

U projektu otkrivanja, dodamo dva svojstva bootstrap.svojstva u src / main / resources:

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

Ova svojstva omogućit će usluzi otkrivanja autentifikaciju pomoću usluge konfiguriranja pri pokretanju.

Ažurirajmo naš otkriće.svojstva u našem Git spremištu

eureka.client.serviceUrl.defaultZone = // diskKorisnik: [zaštićen e-poštom]: 8082 / eureka / eureka.client.register-with-eureka = false eureka.client.fetch-registry = false

Našim smo dodali osnovne vjerodajnice za provjeru autentičnosti otkriće usluga koja mu omogućuje komunikaciju s konfiguracija servis. Dodatno, konfiguriramo Eureka da radi u samostalnom načinu rekavši našoj službi da se ne registrira sama sa sobom.

Predajmo datoteku na git spremište. Inače, promjene neće biti otkrivene.

5. Osiguravanje usluge pristupnika

Naša gateway usluga jedini je dio naše aplikacije koji želimo predstaviti svijetu. Kao takav trebat će mu sigurnost kako bi se osiguralo da samo ovjereni korisnici mogu pristupiti osjetljivim informacijama.

5.1. Konfiguracija sigurnosti

Stvorimo a SecurityConfig klase poput naše usluge otkrivanja i prepišite metode s ovim sadržajem:

@Autowired javna void configureGlobal (AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication (). WithUser ("user"). Password ("password") .roles ("USER"). And (). WithUser ("admin"). Password ( "admin") .roles ("ADMINISTRATOR"); } @Override zaštićena void konfiguracija (HttpSecurity http) {http.authorizeRequests (). AntMatchers ("/ book-service / books") .permitAll (). AntMatchers ("/ eureka / **"). HasRole ("ADMIN") .anyRequest (). authenticated (). and (). formLogin (). and () .logout (). dozvolaAll (). logoutSuccessUrl ("/ book-service / books") .permitAll (). i (). csrf () .disable (); }

Ova je konfiguracija prilično jednostavna. Izjavljujemo sigurnosni filtar s prijavom u obrazac koji osigurava razne krajnje točke.

Sigurnost na / eureka / ** je zaštita nekih statičkih resursa koje ćemo služiti od naše gateway usluge za Eureka statusna stranica. Ako gradite projekt s člankom, kopirajte resurs / statički mapa iz gateway projekta na Githubu u vaš projekt.

Sada modificiramo @EnableRedisHttpSession napomena na našoj klasi klase:

@EnableRedisHttpSession (redisFlushMode = RedisFlushMode.IMMEDIATE)

Način ispiranja postavili smo na trenutno kako bismo odmah nastavili s promjenama na sesiji. To pomaže u pripremi tokena za provjeru autentičnosti za preusmjeravanje.

Na kraju, dodajte a ZuulFilter koji će proslijediti naš token za provjeru autentičnosti nakon prijave:

@Component javna klasa SessionSavingZuulPreFilter proširuje ZuulFilter {@Autowired privatno spremište SessionRepository; @Override public boolean shouldFilter () {return true; } @Override public Object run () {RequestContext context = RequestContext.getCurrentContext (); HttpSession httpSession = context.getRequest (). GetSession (); Sjednica sesije = repozitorij.getSession (httpSession.getId ()); context.addZuulRequestHeader ("Kolačić", "SESSION =" + httpSession.getId ()); return null; } @Override public String filterType () {return "pre"; } @Override public int filterOrder () {return 0; }}

Ovaj će filtar uhvatiti zahtjev jer je preusmjeren nakon prijave i dodati ključ sesije kao kolačić u zaglavlju. Ovo će proširiti provjeru autentičnosti na bilo koju sigurnosnu uslugu nakon prijave.

5.2. Autentifikacija uslugom Config i Discovery

Dodajmo sljedeća svojstva provjere autentičnosti u bootstrap.svojstva uloži u src / glavni / resursi usluge pristupnika:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword eureka.client.serviceUrl.defaultZone = // diskKorisnik: [e-mail zaštićen]: 8082 / eureka /

Dalje, ažurirajmo naš gateway.svojstva u našem Git spremištu

management.security.sessions = uvijek zuul.routes.book-service.path = / book-service / ** zuul.routes.book-service.sensitive-headers = Set-cookie, autorizacija hystrix.command.book-service.execution .isolation.thread .timeoutInMilliseconds = 600000 zuul.routes.rating-service.path = / rating-service / ** zuul.routes.rating-service.sensitive-headers = Set-cookie, autorizacija hystrix.command.rating-service. Execution.isolation.thread .timeoutInMilliseconds = 600000 zuul.routes.discovery.path = / discovery / ** zuul.routes.discovery.sensitive-headers = Set-Cookie, autorizacija zuul.routes.discovery.url = // localhost: 8082 hystrix.command.discovery.execution.isolation.thread .timeoutInMilliseconds = 600000

Dodali smo upravljanje sesijama da uvijek generira sesije, jer imamo samo jedan sigurnosni filtar koji možemo postaviti u datoteci svojstava. Dalje, dodajemo svoje Redis svojstva domaćina i poslužitelja.

Uz to, dodali smo rutu koja će preusmjeriti zahtjeve na našu uslugu otkrivanja. Budući da se samostalna usluga otkrivanja neće registrirati sama sa sobom, moramo je locirati pomoću sheme URL-a.

Možemo ukloniti serviceUrl.defaultZone nekretnina iz gateway.svojstva datoteku u našem konfiguracijskom git spremištu. Ova je vrijednost duplicirana u bootstrap datoteka.

Predajmo datoteku u Git spremište, u suprotnom, promjene neće biti otkrivene.

6. Osiguravanje usluge knjiga

Poslužitelj usluge knjiga sadržavat će osjetljive podatke kojima upravljaju razni korisnici. Ova usluga mora biti osigurana kako bi se spriječilo curenje zaštićenih podataka u našem sustavu.

6.1. Konfiguracija sigurnosti

Da bismo osigurali našu uslugu knjiga, kopirat ćemo SecurityConfig klase s pristupnika i prepišite metodu sa ovim sadržajem:

@Override zaštićena void konfiguracija (HttpSecurity http) {http.httpBasic (). Disable (). AutorizeRequests () .antMatchers ("/ books"). AllowAll () .antMatchers ("/ books / *"). HasAnyRole ("USER "," ADMINISTRATOR ") .authenticated (). I (). Csrf (). Disable (); }

6.2. Svojstva

Dodajte ova svojstva u bootstrap.svojstva uloži u src / glavni / resursi usluge knjige:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword eureka.client.serviceUrl.defaultZone = // diskKorisnik: [e-mail zaštićen]: 8082 / eureka /

Dodajmo svojstva u naš usluga knjiga.svojstva datoteka u našem git spremištu:

management.security.sessions = nikad

Možemo ukloniti serviceUrl.defaultZone nekretnina iz usluga knjiga.svojstva datoteku u našem konfiguracijskom git spremištu. Ova je vrijednost duplicirana u bootstrap datoteka.

Ne zaboravite izvršiti ove promjene kako bi ih usluga knjiga preuzela.

7. Osiguravanje usluge ocjenjivanja

Također treba osigurati ocjenu.

7.1. Konfiguracija sigurnosti

Da bismo osigurali našu uslugu ocjenjivanja, kopirat ćemo SecurityConfig klase s pristupnika i prepišite metodu sa ovim sadržajem:

@Override zaštićena void konfiguracija (HttpSecurity http) {http.httpBasic (). Disable (). AutorizeRequests () .antMatchers ("/ ratings"). HasRole ("USER") .antMatchers ("/ ratings / all"). HasAnyRole ("KORISNIK", "UPRAVNIK"). AnyRequest () .authenticated (). I (). Csrf (). Disable (); }

Možemo izbrisati configureGlobal () metoda iz gateway servis.

7.2. Svojstva

Dodajte ova svojstva u bootstrap.svojstva uloži u src / glavni / resursi usluge ocjenjivanja:

spring.cloud.config.username = configUser spring.cloud.config.password = configPassword eureka.client.serviceUrl.defaultZone = // diskKorisnik: [e-mail zaštićen]: 8082 / eureka /

Dodajmo svojstva u našu ocjenu-uslugu.Svojstva datoteka u našem git spremištu:

management.security.sessions = nikad

Možemo ukloniti serviceUrl.defaultZone svojstvo iz rejting-službe.Svojstva datoteku u našem konfiguracijskom git spremištu. Ova je vrijednost duplicirana u bootstrap datoteka.

Ne zaboravite izvršiti ove promjene kako bi ih usluga za ocjenu preuzela.

8. Trčanje i testiranje

Početak Redis i sve usluge za aplikaciju: konfiguracija, otkrivanje, gateway, knjiga-usluga, i rejting-usluga. Ajmo sad testirati!

Prvo, stvorimo testnu klasu u našem gateway projekt i stvorite metodu za naš test:

javna klasa GatewayApplicationLiveTest {@Test public void testAccess () {...}}

Dalje, postavimo test i potvrdimo da možemo pristupiti svom nezaštićenom / knjiga-usluga / knjige resursa dodavanjem ovog isječka koda unutar naše metode ispitivanja:

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

Pokrenite ovaj test i provjerite rezultate. Ako uočimo kvarove, potvrđujemo da se cjelokupna aplikacija uspješno pokrenula i da su konfiguracije učitane iz našeg konfiguracijskog git spremišta.

Sad testirajmo da li će naši korisnici biti preusmjereni da se prijave prilikom posjeta zaštićenom resursu kao neovlašteni korisnik dodavanjem ovog koda na kraj metode ispitivanja:

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

Ponovno pokrenite test i potvrdite da je uspio.

Dalje, zapravo se prijavimo, a zatim upotrijebimo našu sesiju za pristup zaštićenom korisničkom rezultatu:

Obrazac MultiValueMap = novi LinkedMultiValueMap (); form.add ("korisničko ime", "korisnik"); form.add ("lozinka", "lozinka"); response = testRestTemplate .postForEntity (testUrl + "/ login", obrazac, String.class); 

sada, izvucimo sesiju iz kolačića i proširimo je na sljedeći zahtjev:

Niz sessionCookie = response.getHeaders (). Get ("Set-Cookie") .get (0) .split (";") [0]; HttpHeaders zaglavlja = novi HttpHeaders (); headers.add ("Kolačić", sessionCookie); HttpEntity httpEntity = novi HttpEntity (zaglavlja); 

i zatražite zaštićeni resurs:

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

Ponovno pokrenite test da biste potvrdili rezultate.

Pokušajmo sada pristupiti administratorskom dijelu s istom sesijom:

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

Ponovno pokrenite test i prema očekivanjima pristup administratorskim područjima nam je ograničen kao obični stari korisnik.

Sljedeći test potvrdit će da se možemo prijaviti kao administrator i pristupiti administratorski zaštićenom resursu:

form.clear (); form.add ("korisničko ime", "admin"); form.add ("lozinka", "admin"); response = testRestTemplate .postForEntity (testUrl + "/ login", obrazac, String.class); sessionCookie = response.getHeaders (). get ("Set-Cookie"). get (0) .split (";") [0]; zaglavlja = novi HttpHeaders (); headers.add ("Kolačić", sessionCookie); httpEntity = novi HttpEntity (zaglavlja); response = testRestTemplate.exchange (testUrl + "/ rating-service / ratings / all", HttpMethod.GET, httpEntity, String.class); Assert.assertEquals (HttpStatus.OK, response.getStatusCode ()); Assert.assertNotNull (response.getBody ());

Naš test postaje sve veći! Ali kad pokrenemo, možemo vidjeti da se prijavom kao administrator dobiva pristup administratorskom resursu.

Naš posljednji test je pristup našem serveru za otkrivanje kroz naš pristupnik. Da biste to učinili, dodajte ovaj kôd na kraj našeg testa:

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

Pokrenite ovaj test posljednji put kako biste potvrdili da sve funkcionira. Uspjeh!!!

Je li vam to nedostajalo? Zato što smo se prijavili na našu pristupničku uslugu i pregledavali sadržaj na našim uslugama knjiga, ocjenjivanja i otkrivanja, a da se nismo morali prijaviti na četiri odvojena poslužitelja!

Korištenjem Proljetno zasjedanje za širenje našeg objekta provjere autentičnosti između poslužitelja možemo se jednom prijaviti na pristupnik i tu autentifikaciju koristiti za pristup kontrolorima na bilo kojem broju sigurnosnih usluga.

9. Zaključak

Sigurnost u oblaku sigurno postaje složenija. Ali uz pomoć Proljetna sigurnost i Proljetno zasjedanje, možemo lako riješiti ovo kritično pitanje.

Sada imamo aplikaciju u oblaku sa sigurnošću oko naših usluga. Koristeći Zuul i Proljetno zasjedanje možemo prijaviti korisnike u samo jednoj usluzi i proširiti tu provjeru autentičnosti na cijelu našu aplikaciju. To znači da našu aplikaciju možemo lako razbiti na odgovarajuće domene i osigurati svaku od njih kako smatramo potrebnim.

Kao i uvijek izvorni kod možete pronaći na GitHubu.


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