Vårsikkerhet: Utforsk JDBC-autentisering

Utholdenhetstopp

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

1. Oversikt

I denne korte opplæringen vil vi utforske mulighetene som Spring tilbyr for å utføre JDBC-autentisering ved hjelp av en eksisterende Datakilde konfigurasjon.

I vår godkjenning med et databasestøttet UserDetailsService-innlegg analyserte vi en tilnærming for å oppnå dette ved å implementere UserDetailService grensesnitt oss selv.

Denne gangen bruker vi AuthenticationManagerBuilder # jdbcAuthentication direktiv for å analysere fordeler og ulemper ved denne enklere tilnærmingen.

2. Bruke en innebygd H2-tilkobling

Først og fremst vil vi analysere hvordan vi kan oppnå autentisering ved hjelp av en innebygd H2-database.

Dette er enkelt å oppnå fordi det meste av Spring Boots autokonfigurasjon er klargjort for dette scenariet.

2.1. Avhengigheter og databasekonfigurasjon

La oss starte med å følge instruksjonene i vårt forrige Spring Boot With H2 Database-innlegg for å:

  1. Inkluder det tilsvarende spring-boot-starter-data-jpa og h2 avhengigheter
  2. Konfigurer databaseforbindelsen med applikasjonsegenskaper
  3. Aktiver H2-konsollen

2.2. Konfigurerer JDBC-autentisering

Vi bruker Spring Securitys AuthenticationManagerBuilder konfigurasjonshjelp for å konfigurere JDBC-autentisering:

@Autowired private DataSource dataSource; @Autowired public void configureGlobal (AuthenticationManagerBuilder auth) kaster unntak {auth.jdbcAuthentication () .dataSource (dataSource) .withDefaultSchema () .withUser (User.withUsername ("user") .password (passwordEncoder ().). Encode ("passord") " ) .roles ("BRUKER")); } @Bean public PasswordEncoder passwordEncoder () {return new BCryptPasswordEncoder (); }

Som vi ser, bruker vi den autokonfigurerte Datakilde. De med standardskjema direktivet legger til et databasescript som fyller ut standardskjemaet, slik at brukere og myndigheter kan lagres.

Dette grunnleggende brukerskjemaet er dokumentert i Spring Security Appendix.

Til slutt oppretter vi en oppføring i databasen med en standardbruker programmatisk.

2.3. Bekrefte konfigurasjonen

La oss lage et veldig enkelt endepunkt for å hente det autentiserte Rektor informasjon:

@RestController @RequestMapping ("/ principal") offentlig klasse UserController {@GetMapping public Rektor retrievePrincipal (Rektor rektor) {retur rektor; }}

I tillegg vil vi sikre dette endepunktet, samtidig som vi gir tilgang til H2-konsollen:

@Configuration offentlig klasse SecurityConfiguration utvider WebSecurityConfigurerAdapter {@Override beskyttet ugyldig konfigurasjon (HttpSecurity httpSecurity) kaster Unntak {httpSecurity.authorizeRequests () .antMatchers ("/ h2-console / **") .permitAll () .anyRequesticated () .a. .og () .formLogin (); httpSecurity.csrf () .ignoringAntMatchers ("/ h2-konsoll / **"); httpSecurity.headers () .frameOptions () .sameOrigin (); }}

Merk: her gjengir vi den tidligere sikkerhetskonfigurasjonen implementert av Spring Boot, men i et virkelig scenario vil vi sannsynligvis ikke aktivere H2-konsollen i det hele tatt.

Nå kjører vi applikasjonen og blar gjennom H2-konsollen. Vi kan bekrefte det Spring lager to tabeller i den innebygde databasen vår: brukere og autoriteter.

Strukturen deres tilsvarer strukturen definert i Spring Security Appendix vi nevnte tidligere.

Til slutt, la oss godkjenne og be om /rektor sluttpunkt for å se relatert informasjon, inkludert brukerinformasjon.

2.4. Under panseret

I begynnelsen av dette innlegget presenterte vi en lenke til en opplæring som forklarte hvordan vi kan tilpasse databasestøttet autentisering ved å implementere UserDetailsService grensesnitt; Vi anbefaler på det sterkeste å se på det innlegget hvis vi vil forstå hvordan ting fungerer under panseret.

I dette tilfellet stoler vi på en implementering av det samme grensesnittet levert av Spring Security; de JdbcDaoImpl.

Hvis vi utforsker denne klassen, får vi se UserDetails implementering den bruker, og mekanismene for å hente brukerinformasjon fra databasen.

Dette fungerer ganske bra for dette enkle scenariet, men det har noen ulemper hvis vi vil tilpasse databaseskjemaet, eller til og med hvis vi vil bruke en annen databaseleverandør.

La oss se hva som skjer hvis vi endrer konfigurasjonen til å bruke en annen JDBC-tjeneste.

3. Tilpasse skjemaet for en annen database

I denne delen konfigurerer vi autentisering på prosjektet vårt ved hjelp av en MySQL-database.

Som vi skal se neste, for å oppnå dette, må vi unngå å bruke standardskjemaet og gi vårt eget.

3.1. Avhengigheter og databasekonfigurasjon

For det første, la oss fjerne h2 avhengighet og erstatt den for det tilsvarende MySQL-biblioteket:

 mysql mysql-connector-java 8.0.17 

Som alltid kan vi slå opp den nyeste versjonen av biblioteket i Maven Central.

La oss nå stille applikasjonsegenskapene på nytt:

spring.datasource.url = jdbc: mysql: // localhost: 3306 / jdbc_authentication spring.datasource.username = root spring.datasource.password = pass

3.2. Kjører standardkonfigurasjonen

Selvfølgelig bør disse tilpasses for å koble til din kjørende MySQL-server. For testformål, her starter vi en ny forekomst ved bruk av Docker:

docker run -p 3306: 3306 --name bael-mysql -e MYSQL_ROOT_PASSWORD = pass -e MYSQL_DATABASE = jdbc_authentication mysql: siste

La oss kjøre prosjektet nå for å se om standardkonfigurasjonen passer for en MySQL-database.

Egentlig vil ikke applikasjonen komme i gang på grunn av en SQLSyntaxErrorException. Dette gir faktisk mening; som sagt, det meste av standard autokonfigurasjon er egnet for en HSQLDB.

I dette tilfellet, DDL-skriptet som fulgte med med standardskjema direktivet bruker en dialekt som ikke passer for MySQL.

Derfor må vi unngå å bruke dette skjemaet og gi vårt eget.

3.3. Tilpasse autentiseringskonfigurasjonen

Siden vi ikke vil bruke standardskjemaet, må vi fjerne den riktige setningen fra AuthenticationManagerBuilder konfigurasjon.

Siden vi skal tilby våre egne SQL-skript, kan vi også unngå å prøve å opprette brukeren programmatisk:

@Autowired public void configureGlobal (AuthenticationManagerBuilder auth) kaster Unntak {auth.jdbcAuthentication () .dataSource (dataSource); }

La oss nå se på initialiseringsskriptene for databasen.

Først vår schema.sql:

OPPRETT TABELLbrukere (brukernavn VARCHAR (50) IKKE NULL, passord VARCHAR (100) IKKE NULL, aktivert TINYINT IKKE NULL STANDARD 1, PRIMÆR NØKKEL (brukernavn)); OPPRETT TABELLmyndigheter (brukernavn VARCHAR (50) IKKE NULL, autoritet VARCHAR (50) IKKE NULL, UTENLANDSK TAST (brukernavn) REFERANSER brukere (brukernavn)); OPPRETT UNIK INDEKS ix_auth_username på autoriteter (brukernavn, autoritet);

Og så, vår data.sql:

- Brukerbruker / pass INSERT INTO-brukere (brukernavn, passord, aktivert) verdier ('bruker', '$ 2a $ 10 $ 8. UnVuG9HHgffUDAlk8qfOuVGkqRzgVymGe07xd00DMxs.AQubh4a', 1); INSERT IN TO Authoritys (brukernavn, autoritet) verdier ('bruker', 'ROLE_USER');

Til slutt bør vi endre noen andre applikasjonsegenskaper:

  • Siden vi ikke forventer at dvalemodus skal opprette skjemaet nå, bør vi deaktivere ddl-auto eiendom
  • Som standard initialiserer Spring Boot datakilden bare for innebygde databaser, noe som ikke er tilfelle her:
spring.datasource.initialization-mode = alltid spring.jpa.hibernate.ddl-auto = ingen

Som et resultat skal vi nå kunne starte applikasjonen riktig, autentisere og hente Rektor data fra sluttpunktet.

4. Tilpasse spørsmålene for et annet skjema

La oss gå et skritt videre. Tenk deg at standardskjemaet bare ikke passer for våre behov.

4.1. Endring av standardskjema

Tenk deg for eksempel at vi allerede har en database med en struktur som er litt forskjellig fra standard:

OPPRETT TABELL bael_users (navn VARCHAR (50) IKKE NULL, e-post VARCHAR (50) IKKE NULL, passord VARCHAR (100) IKKE NULL, aktivert TINYINT IKKE NULL STANDARD 1, PRIMÆR NØKKEL (e-post)); OPPRETT TABELLmyndigheter (e-post VARCHAR (50) IKKE NULL, autoritet VARCHAR (50) IKKE NULL, UTENLANDSK Nøkkel (e-post) REFERANSER bael_users (e-post)); OPPRETT UNIK INDEKS ix_auth_email på myndigheter (e-post, autoritet);

Til slutt, vår data.sql skriptet vil også bli tilpasset denne endringen:

- Bruker [e-postbeskyttet] / pass INSERT INTO bael_users (navn, e-postadresse, passord, aktivert) verdier ('bruker', '[e-postbeskyttet]', '$ 2a $ 10 $ 8.UnVuG9HHgffUDAlk8qfOuVGkqRzgVymGe07xd00DMxs.AQubh4a', 1); INNSETT I autoriteter (e-post, autoritet) verdier ('[email protected]', 'ROLE_USER');

4.2. Kjører applikasjonen med det nye skjemaet

La oss starte applikasjonen vår. Det initialiseres riktig, noe som er fornuftig siden skjemaet vårt er riktig.

Nå, hvis vi prøver å logge inn, vil vi finne at det blir bedt om en feil når vi presenterer legitimasjonen.

Spring Security leter fortsatt etter en brukernavn felt i databasen. Heldig for oss gir JDBC Authentication-konfigurasjonen muligheten for tilpasse spørringene som brukes til å hente brukeropplysninger i autentiseringsprosessen.

4.3. Tilpasse søkene

Det er ganske enkelt å tilpasse spørsmålene. Vi må ganske enkelt gi våre egne SQL-setninger når vi konfigurerer AuthenticationManagerBuilder:

@Autowired public void configureGlobal (AuthenticationManagerBuilder auth) kaster Unntak {auth.jdbcAuthentication () .dataSource (dataSource) .usersByUsernameQuery ("select email, password, enabled" + "from bael_users" + "where email =?") .AuthoritiesByUs velg e-post, autoritet "+" fra myndigheter "+" der e-post =? "); }

Vi kan starte applikasjonen en gang til, og få tilgang til /rektor sluttpunkt ved hjelp av de nye legitimasjonene.

5. Konklusjon

Som vi kan se, er denne tilnærmingen mye enklere enn å måtte lage vår egen UserDetailServiceimplementering, som innebærer en vanskelig prosess; skape enheter og klasser som implementerer UserDetail grensesnitt og legge til arkiver i prosjektet vårt.

Ulempen er selvfølgelig den lille fleksibiliteten den gir når databasen vår eller logikken vår skiller seg fra standardstrategien levert av Spring Security-løsningen.

Til slutt kan vi se på de komplette eksemplene i GitHub-depotet vårt. Vi inkluderte til og med et eksempel på PostgreSQL som vi ikke viste i denne opplæringen, bare for å holde ting enkelt.

Persistensbunn

Jeg kunngjorde nettopp det nye Lær våren kurs, med fokus på det grunnleggende i vår 5 og vårstøvel 2:

>> KONTROLLER KURSET

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