Spring Security: JDBC-verificatie verkennen

Persistentie top

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS

1. Overzicht

In deze korte tutorial onderzoeken we de mogelijkheden die Spring biedt om JDBC-verificatie uit te voeren met een bestaand Databron configuratie.

In onze Authentication with a Database-backed UserDetailsService-post, hebben we één benadering geanalyseerd om dit te bereiken, door de implementatie van de UserDetailService interface onszelf.

Deze keer maken we gebruik van de AuthenticationManagerBuilder # jdbcAuthentication richtlijn om de voor- en nadelen van deze eenvoudigere aanpak te analyseren.

2. Een ingebouwde H2-verbinding gebruiken

Allereerst zullen we analyseren hoe we authenticatie kunnen bereiken met behulp van een embedded H2-database.

Dit is gemakkelijk te bereiken omdat de meeste autoconfiguraties van Spring Boot out-of-the-box voor dit scenario zijn voorbereid.

2.1. Afhankelijkheden en databaseconfiguratie

Laten we beginnen met het volgen van de instructies van onze vorige Spring Boot With H2 Database-post naar:

  1. Voeg de bijbehorende spring-boot-starter-data-jpa en h2 afhankelijkheden
  2. Configureer de databaseverbinding met applicatie-eigenschappen
  3. Schakel de H2-console in

2.2. JDBC-verificatie configureren

We gebruiken Spring Security's AuthenticationManagerBuilder configuratiehulp om JDBC-verificatie te configureren:

@Autowired privé DataSource dataSource; @Autowired public void configureGlobal (AuthenticationManagerBuilder auth) genereert Uitzondering {auth.jdbcAuthentication () .dataSource (dataSource) .withDefaultSchema () .withUser (User.withUsername ("user") .password (passwordEncoder (). Encode ("pass") ) .roles ("GEBRUIKER")); } @Bean public PasswordEncoder passwordEncoder () {retourneer nieuwe BCryptPasswordEncoder (); }

Zoals we kunnen zien, gebruiken we het automatisch geconfigureerde Databron. De withDefaultSchema richtlijn voegt een databasescript toe dat het standaardschema vult, zodat gebruikers en machtigingen kunnen worden opgeslagen.

Dit basisschema voor gebruikers wordt gedocumenteerd in de Spring Security-bijlage.

Ten slotte maken we programmatisch een vermelding in de database met een standaardgebruiker.

2.3. De configuratie verifiëren

Laten we een heel eenvoudig eindpunt maken om het geverifieerde Opdrachtgever informatie:

@RestController @RequestMapping ("/ principal") public class UserController {@GetMapping public Principal retrievePrincipal (Principal principal) {return principal; }}

Bovendien beveiligen we dit eindpunt, terwijl we toegang tot de H2-console toestaan:

@Configuration public class SecurityConfiguration breidt WebSecurityConfigurerAdapter uit {@Override protected void configure (HttpSecurity httpSecurity) genereert uitzondering {httpSecurity.authorizeRequests () .antMatchers ("/ h2-console / **") .permitAll () .anyRhenticated (). .en () .formLogin (); httpSecurity.csrf () .ignoringAntMatchers ("/ h2-console / **"); httpSecurity.headers () .frameOptions () .sameOrigin (); }}

Opmerking: hier reproduceren we de vroegere beveiligingsconfiguratie geïmplementeerd door Spring Boot, maar in een realistisch scenario zullen we de H2-console waarschijnlijk helemaal niet inschakelen.

Nu zullen we de applicatie uitvoeren en door de H2-console bladeren. We kunnen dat verifiëren De lente maakt twee tabellen aan in onze embedded database: gebruikers en autoriteiten.

Hun structuur komt overeen met de structuur die is gedefinieerd in de Spring Security-bijlage die we eerder noemden.

Laten we tot slot verifiëren en het / opdrachtgever eindpunt om de gerelateerde informatie te zien, inclusief de gebruikersgegevens.

2.4. Onder de motorkap

Aan het begin van dit bericht presenteerden we een link naar een tutorial waarin werd uitgelegd hoe we kunnen database-gesteunde authenticatie aanpassen door het UserDetailsService koppel; we raden ten zeerste aan om die post te bekijken als we willen begrijpen hoe de dingen werken onder de motorkap.

In dit geval vertrouwen we op een implementatie van dezelfde interface geleverd door Spring Security; de JdbcbaoImpl.

Als we deze klasse verkennen, zien we de Gebruikersdetails implementatie die het gebruikt, en de mechanismen om gebruikersinformatie uit de database op te halen.

Dit werkt redelijk goed voor dit eenvoudige scenario, maar het heeft enkele nadelen als we het databaseschema willen aanpassen of zelfs als we een andere databaseleverancier willen gebruiken.

Laten we eens kijken wat er gebeurt als we de configuratie wijzigen om een ‚Äč‚Äčandere JDBC-service te gebruiken.

3. Aanpassen van het schema voor een andere database

In deze sectie zullen we authenticatie op ons project configureren met behulp van een MySQL-database.

Zoals we hierna zullen zien, moeten we, om dit te bereiken, het gebruik van het standaardschema vermijden en ons eigen schema opgeven.

3.1. Afhankelijkheden en databaseconfiguratie

Laten we om te beginnen het h2 afhankelijkheid en vervang deze voor de bijbehorende MySQL-bibliotheek:

 mysql mysql-connector-java 8.0.17 

Zoals altijd kunnen we de nieuwste versie van de bibliotheek opzoeken in Maven Central.

Laten we nu de applicatie-eigenschappen opnieuw instellen:

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

3.2. De standaardconfiguratie uitvoeren

Deze moeten natuurlijk worden aangepast om verbinding te maken met uw actieve MySQL-server. Voor testdoeleinden starten we hier een nieuwe instantie met Docker:

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

Laten we het project nu uitvoeren om te zien of de standaardconfiguratie geschikt is voor een MySQL-database.

Eigenlijk kan de applicatie niet starten vanwege een SQLSyntaxErrorException. Dit is eigenlijk logisch; zoals we al zeiden, de meeste standaard autoconfiguratie is geschikt voor een HSQLDB.

In dit geval, het DDL-script dat is meegeleverd met de withDefaultSchema richtlijn gebruikt een dialect dat niet geschikt is voor MySQL.

Daarom moeten we het gebruik van dit schema vermijden en ons eigen schema bieden.

3.3. De authenticatieconfiguratie aanpassen

Omdat we het standaardschema niet willen gebruiken, moeten we de juiste instructie verwijderen uit het AuthenticationManagerBuilder configuratie.

Omdat we onze eigen SQL-scripts leveren, kunnen we voorkomen dat we proberen de gebruiker programmatisch te maken:

@Autowired public void configureGlobal (AuthenticationManagerBuilder auth) genereert Uitzondering {auth.jdbcAuthentication () .dataSource (dataSource); }

Laten we nu eens kijken naar de initialisatiescripts van de database.

Ten eerste onze schema.sql:

CREATE TABLE-gebruikers (gebruikersnaam VARCHAR (50) NOT NULL, wachtwoord VARCHAR (100) NOT NULL, ingeschakeld TINYINT NOT NULL STANDAARD 1, PRIMAIRE SLEUTEL (gebruikersnaam)); CREATE TABLE autoriteiten (gebruikersnaam VARCHAR (50) NOT NULL, autoriteit VARCHAR (50) NOT NULL, BUITENLANDSE SLEUTEL (gebruikersnaam) REFERENTIES gebruikers (gebruikersnaam)); MAAK UNIEKE INDEX ix_auth_username op autoriteiten (gebruikersnaam, autoriteit);

En dan onze data.sql:

- Gebruiker gebruiker / pass INSERT IN gebruikers (gebruikersnaam, wachtwoord, ingeschakeld) waarden ('gebruiker', '$ 2a $ 10 $ 8.UnVuG9HHgffUDAlk8qfOuVGkqRzgVymGe07xd00DMxs.AQubh4a', 1); INVOEGEN IN autoriteiten (gebruikersnaam, autoriteit) waarden ('gebruiker', 'ROLE_USER');

Ten slotte moeten we enkele andere applicatie-eigenschappen wijzigen:

  • Omdat we niet verwachten dat Hibernate het schema nu zal maken, moeten we het ddl-auto eigendom
  • Standaard initialiseert Spring Boot de gegevensbron alleen voor embedded databases, wat hier niet het geval is:
spring.datasource.initialization-mode = altijd spring.jpa.hibernate.ddl-auto = geen

Als gevolg hiervan zouden we nu onze applicatie correct moeten kunnen starten, waarbij we het Opdrachtgever gegevens van het eindpunt.

4. De query's aanpassen voor een ander schema

Laten we een stap verder gaan. Stel je voor dat het standaardschema gewoon niet geschikt is voor onze behoeften.

4.1. Het standaardschema wijzigen

Stel je voor dat we bijvoorbeeld al een database hebben met een structuur die enigszins afwijkt van de standaard:

CREATE TABLE bael_users (naam VARCHAR (50) NOT NULL, e-mail VARCHAR (50) NOT NULL, wachtwoord VARCHAR (100) NOT NULL, ingeschakeld TINYINT NOT NULL STANDAARD 1, PRIMAIRE SLEUTEL (e-mail)); CREATE TABLE autoriteiten (e-mail VARCHAR (50) NOT NULL, autoriteit VARCHAR (50) NOT NULL, FOREIGN KEY (e-mail) REFERENTIES bael_users (e-mail)); CREËER UNIEKE INDEX ix_auth_email op autoriteiten (e-mail, autoriteit);

Eindelijk, onze data.sql script zal ook aan deze wijziging worden aangepast:

- Gebruiker [e-mail beschermd] / pass INVOEGEN IN bael_users (naam, e-mail, wachtwoord, ingeschakeld) waarden ('gebruiker', '[e-mail beschermd]', '$ 2a $ 10 $ 8.UnVuG9HHgffUDAlk8qfOuVGkqRzgVymGe07xd00DMxs.AQubh4a', 1); INVOEGEN IN autoriteiten (e-mail, autoriteit) waarden ('[e-mail beschermd]', 'ROLE_USER');

4.2. De toepassing uitvoeren met het nieuwe schema

Laten we onze applicatie starten. Het wordt correct geïnitialiseerd, wat logisch is omdat ons schema correct is.

Als we nu proberen in te loggen, zullen we zien dat er een foutmelding wordt weergegeven bij het presenteren van de inloggegevens.

Spring Security is nog op zoek naar een gebruikersnaam veld in de database. Gelukkig voor ons biedt de JDBC Authentication-configuratie de mogelijkheid van het aanpassen van de zoekopdrachten die worden gebruikt om gebruikersgegevens op te halen tijdens het authenticatieproces.

4.3. De zoekopdrachten aanpassen

Het aanpassen van de vragen is vrij eenvoudig. We hoeven alleen maar onze eigen SQL-instructies op te geven bij het configureren van het AuthenticationManagerBuilder:

@Autowired public void configureGlobal (AuthenticationManagerBuilder auth) genereert Uitzondering {auth.jdbcAuthentication () .dataSource (dataSource) .usersByUsernameQuery ("selecteer e-mail, wachtwoord, ingeschakeld" + "van bael_users" + "waar e-mail =?") .AuthoritiesByUs selecteer e-mail, autoriteit "+" van autoriteiten "+" waar e-mail =? "); }

We kunnen de applicatie opnieuw starten en toegang krijgen tot het / opdrachtgever eindpunt met behulp van de nieuwe referenties.

5. Conclusie

Zoals we kunnen zien, is deze benadering veel eenvoudiger dan onze eigen benadering te moeten creëren UserDetailServiceimplementatie, wat een moeizaam proces inhoudt; entiteiten en klassen maken die het UserDetail interface en het toevoegen van repositories aan ons project.

Het nadeel is natuurlijk de weinige flexibiliteit die het biedt wanneer onze database of onze logica verschilt van de standaardstrategie geleverd door de Spring Security-oplossing.

Ten slotte kunnen we de volledige voorbeelden in onze GitHub-repository bekijken. We hebben zelfs een voorbeeld met PostgreSQL toegevoegd dat we niet in deze tutorial hebben laten zien, alleen om het simpel te houden.

Persistentie onderaan

Ik heb zojuist het nieuwe aangekondigd Leer de lente natuurlijk, gericht op de basisprincipes van Spring 5 en Spring Boot 2:

>> BEKIJK DE CURSUS