Spring Boot - OAuth2 und JWT

Gruß, Freunde! Morgen beginnen die ersten Klassen im neuen Thread des Kurses "Developer on Spring Framework" . In diesem Zusammenhang teilen wir traditionell nützliches Material zu diesem Thema.



In diesem Artikel werden wir die Verwendung von OAuth2 und JWT in Verbindung mit Spring Boot und Spring Security untersuchen.

Autorisierungsserver


Ein Autorisierungsserver ist die wichtigste Komponente in der Web-API-Sicherheitsarchitektur. Der Autorisierungsserver fungiert als einzelner Autorisierungspunkt und ermöglicht Ihren Anwendungen und HTTP-Endpunkten, die Funktionen Ihrer Anwendung zu definieren.

Ressourcenserver


Der Autorisierungsserver stellt Clients ein Zugriffstoken für den Zugriff auf die HTTP-Endpunkte des Ressourcenservers zur Verfügung. Ein Ressourcenserver ist eine Sammlung von Bibliotheken, die HTTP-Endpunkte, statische Ressourcen und dynamische Webseiten enthalten.

OAuth2


OAuth2 ist ein Autorisierungsprotokoll, mit dem ein Client (Dritter) auf die Ressourcen Ihrer Anwendung zugreifen kann. Um eine OAuth2-Anwendung zu erstellen, müssen wir den Grant-Typ (Autorisierungscode), die Client-ID und das Client-Geheimnis kennen.

JWT-Token


Ein JWT-Token ist ein JSON-Web-Token. Es wird verwendet, um sichere Identifikationsinformationen (Ansprüche) zwischen zwei Parteien darzustellen. Weitere Informationen zu JWT-Token finden Sie unter www.jwt.io.

Wir werden eine OAuth2-Anwendung mit JWT-Token erstellen, die einen Autorisierungsserver und einen Ressourcenserver enthält.

Zuerst müssen wir die Abhängigkeiten zu unserer Build-Datei hinzufügen.

Maven-Benutzer können pom.xml die folgenden Abhängigkeiten hinzufügen.

 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> 

Anmerkung des Übersetzers - Für Java, das älter als 9 Jahre ist, müssen Sie außerdem die folgenden Abhängigkeiten hinzufügen:

 <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency> 

Gradle-Benutzer können der Datei build.gradle die folgenden Abhängigkeiten build.gradle .

 compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.springframework.security:spring-security-test') compile("org.springframework.security.oauth:spring-security-oauth2") compile('org.springframework.security:spring-security-jwt') compile("org.springframework.boot:spring-boot-starter-jdbc") compile("com.h2database:h2:1.4.191") 

wo

  • Spring Boot Starter Security - implementiert Spring Security
  • Spring Security OAuth2 - implementiert OAUTH2-Strukturen für den Betrieb des Autorisierungsservers und des Ressourcenservers.
  • Spring Security JWT - Generiert JWT-Token
  • Spring Boot Starter JDBC - Datenbankzugriff zur Benutzerüberprüfung.
  • Spring Boot Starter Web - Stellt HTTP-Endpunkte bereit.
  • H2-Datenbank - speichert Benutzerinformationen zur Authentifizierung und Autorisierung.

Die vollständige Datei pom.xml unten angezeigt.

 <?xml version = "1.0" encoding = "UTF-8"?> <project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tutorialspoint</groupId> <artifactId>websecurityapp</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>websecurityapp</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 

Gradle — build.gradle

 buildscript { ext { springBootVersion = '1.5.9.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' group = 'com.tutorialspoint' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.springframework.security:spring-security-test') compile("org.springframework.security.oauth:spring-security-oauth2") compile('org.springframework.security:spring-security-jwt') compile("org.springframework.boot:spring-boot-starter-jdbc") compile("com.h2database:h2:1.4.191") } 

@EnableAuthorizationServer @EnableResourceServer jetzt in der Hauptanwendungsdatei von Spring Boot die Anmerkungen @EnableAuthorizationServer und @EnableResourceServer damit die Anwendung sowohl als Autorisierungsserver als auch als Ressourcenserver fungiert.

Fügen Sie außerdem einen einfachen HTTP-Endpunkt (/ products) hinzu, um mithilfe eines JWT-Tokens auf die durch Spring Security geschützte API zuzugreifen.

 package com.tutorialspoint.websecurityapp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableAuthorizationServer @EnableResourceServer @RestController public class WebsecurityappApplication { public static void main(String[] args) { SpringApplication.run(WebsecurityappApplication.class, args); } @RequestMapping(value = "/products") public String getProductName() { return "Honey"; } } 

Definieren Sie eine POJO-Klasse zum Speichern von Benutzerauthentifizierungsinformationen.

 package com.tutorialspoint.websecurityapp; import java.util.ArrayList; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; public class UserEntity { private String username; private String password; private Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>(); public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Collection<GrantedAuthority> getGrantedAuthoritiesList() { return grantedAuthoritiesList; } public void setGrantedAuthoritiesList(Collection<GrantedAuthority> grantedAuthoritiesList) { this.grantedAuthoritiesList = grantedAuthoritiesList; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } } 

Fügen Sie als Nächstes zur Authentifizierung die CustomUser-Klasse hinzu, die org.springframework.security.core.userdetails.User .

 package com.tutorialspoint.websecurityapp; import org.springframework.security.core.userdetails.User; public class CustomUser extends User { private static final long serialVersionUID = 1L; public CustomUser(UserEntity user) { super(user.getUsername(), user.getPassword(), user.getGrantedAuthoritiesList()); } } 

Erstellen Sie eine @Repository- , um Benutzerinformationen aus der Datenbank abzurufen und die Berechtigungen ROLE_SYSTEMADMIN hinzuzufügen. Diese Klasse wird auch in CustomDetailsService .

 package com.tutorialspoint.websecurityapp; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Repository; @Repository public class OAuthDao { @Autowired private JdbcTemplate jdbcTemplate; public UserEntity getUserDetails(String username) { Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>(); String userSQLQuery = "SELECT * FROM USERS WHERE USERNAME=?"; List<UserEntity> list = jdbcTemplate.query(userSQLQuery, new String[] { username }, (ResultSet rs, int rowNum) -> { UserEntity user = new UserEntity(); user.setUsername(username); user.setPassword(rs.getString("PASSWORD")); return user; }); if (list.size() > 0) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_SYSTEMADMIN"); grantedAuthoritiesList.add(grantedAuthority); list.get(0).setGrantedAuthoritiesList(grantedAuthoritiesList); return list.get(0); } return null; } } 

Um ein DAO-Repository UserDetailsService , können Sie Ihren UserDetailsService erstellen, der von org.springframework.security.core.userdetails.UserDetailsService (siehe unten).

 package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; @Service public class CustomDetailsService implements UserDetailsService { @Autowired OAuthDao oauthDao; @Override public CustomUser loadUserByUsername(final String username) throws UsernameNotFoundException { UserEntity userEntity = null; try { userEntity = oauthDao.getUserDetails(username); CustomUser customUser = new CustomUser(userEntity); return customUser; } catch (Exception e) { e.printStackTrace(); throw new UsernameNotFoundException("User " + username + " was not found in the database"); } } } 

Erstellen Sie als Nächstes eine @onfiguration- , um Web Security zu aktivieren. Definieren Sie darin Kennwortverschlüsselungsparameter ( BCryptPasswordEncoder ) und die AuthenticationManager Bean.
Diese SecurityConfiguration Klasse muss von der WebSecurityConfigurerAdapter Klasse erben.

 package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private CustomDetailsService customDetailsService; @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); } @Override @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customDetailsService).passwordEncoder(encoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.NEVER); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } 

Fügen Sie nun eine Klasse hinzu, um OAuth2 zu konfigurieren. Definieren Sie darin die Client-ID, das Client-Geheimnis, den JwtAccessTokenConverter sowie private und öffentliche Schlüssel zum Signieren und Überprüfen des Tokens und konfigurieren Sie ClientDetailsServiceConfigurer für gültige Token-Bereiche.

 package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; @Configuration public class OAuth2Config extends AuthorizationServerConfigurerAdapter { private String clientid = "tutorialspoint"; private String clientSecret = "my-secret-key"; private String privateKey = "private key"; private String publicKey = "public key"; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Bean public JwtAccessTokenConverter tokenEnhancer() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(privateKey); converter.setVerifierKey(publicKey); return converter; } @Bean public JwtTokenStore tokenStore() { return new JwtTokenStore(tokenEnhancer()); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore()) .accessTokenConverter(tokenEnhancer()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(clientid).secret(clientSecret).scopes("read", "write") .authorizedGrantTypes("password", "refresh_token").accessTokenValiditySeconds(20000) .refreshTokenValiditySeconds(20000); } } 

Erstellen Sie nun den privaten und öffentlichen Schlüssel mit openssl .
Um einen privaten Schlüssel zu generieren, können Sie die folgenden Befehle verwenden:

 openssl genrsa -out jwt.pem 2048 openssl rsa -in jwt.pem 

Für öffentlichen Schlüssel -

 openssl rsa -in jwt.pem -pubout 

Fügen Sie für Spring Boot, das älter als Version 1.5 ist, der Datei application.properties die folgende Eigenschaft hinzu (um die Filterreihenfolge der OAuth2-Ressourcen zu bestimmen).

 security.oauth2.resource.filter-order=3 

Wenn Sie eine YAML-Datei verwenden, fügen Sie Folgendes hinzu.

 security: oauth2: resource: filter-order: 3 

Erstellen schema.sql data.sql schema.sql und data.sql im classpath im src/main/resources/directory , um die Anwendung mit der H2-Datenbank zu verbinden.

Die Datei schema.sql sieht folgendermaßen aus:

 CREATE TABLE USERS (ID INT PRIMARY KEY, USERNAME VARCHAR(45), PASSWORD VARCHAR(60));  data.sql: INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES ( 1, 'tutorialspoint@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG'); INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES ( 2, 'myemail@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG'); 

Hinweis - Das Kennwort in der Datenbanktabelle muss im Bcrypt Encoder-Format gespeichert sein.
Sie können eine ausführbare JAR-Datei erstellen und die Spring Boot-Anwendung mit den folgenden Maven- oder Gradle-Befehlen ausführen.


Für Maven können Sie den folgenden Befehl verwenden:

 mvn clean install 

Nach "BUILD SUCCESS" finden Sie die JAR-Dateien im target .

Für Gradle können Sie den Befehl verwenden -

 gradle clean build 

Nach "BUILD SUCCESSFUL" finden Sie die JAR-Dateien im Verzeichnis build/libs .
Führen Sie nun die JAR-Datei mit dem Befehl - aus.

java –jar < JARFILE >

Die Anwendung wurde in Tomcat auf Port 8080 gestartet.



Senden Sie nun eine POST-Anfrage über POSTMAN, um ein OAUTH2-Token zu erhalten.

http://localhost:8080/oauth/token
Fügen Sie nun die Anforderungsheader hinzu -

  • Autorisierung - Grundlegend mit Ihrer Kunden-ID und Ihrem Kundengeheimnis.
  • Inhaltstyp - application / x-www-form-urlencoded



Und Parameter anfordern -

  • grant_type = Passwort
  • Benutzername = Ihr Name
  • Passwort = Ihr Passwort



Führen Sie nun aus und erhalten Sie access_token wie gezeigt.



Erstellen Sie nun eine Anforderung an die Ressourcenserver-API mit einem Bearer-Token im Header.



Wir erhalten das Ergebnis wie unten gezeigt.



Wir warten auf Ihre Kommentare und informieren Sie darüber, dass Sie bis zum 31. Mai zum Sonderpreis am Kurs teilnehmen können.

Source: https://habr.com/ru/post/de453664/


All Articles