Spring Boot - OAuth2 et JWT

Salut, mes amis! Demain, les premiers cours commenceront dans le nouveau fil du cours "Developer on Spring Framework" . À cet Ă©gard, nous partageons traditionnellement des informations utiles sur le sujet.



Dans cet article, nous explorerons l'utilisation d'OAuth2 et de JWT conjointement avec Spring Boot et Spring Security.

Serveur d'autorisation


Un serveur d'autorisation est le composant le plus important de l'architecture de sécurité de l'API Web. Le serveur d'autorisation agit comme un point d'autorisation unique et permet à vos applications et points de terminaison HTTP de définir les fonctions de votre application.

Serveur de ressources


Le serveur d'autorisation fournit aux clients un jeton d'accÚs pour accéder aux points de terminaison HTTP du serveur de ressources. Un serveur de ressources est une collection de bibliothÚques qui contient des points de terminaison HTTP, des ressources statiques et des pages Web dynamiques.

OAuth2


OAuth2 est un protocole d'autorisation qui permet à un client (tiers) d'accéder aux ressources de votre application. Pour créer une application OAuth2, nous devons connaßtre le type de subvention (code d'autorisation), l'ID client et le secret client.

Jeton JWT


Un jeton JWT est un jeton Web JSON. Il est utilisé pour représenter des informations d'identification sécurisées (réclamations) entre deux parties. Vous pouvez trouver plus d'informations sur les jetons JWT sur www.jwt.io.

Nous allons créer une application OAuth2 à l'aide de jetons JWT, qui comprendra un serveur d'autorisation et un serveur de ressources.

Tout d'abord, nous devons ajouter les dépendances à notre fichier de construction.

Les utilisateurs Maven peuvent ajouter les dépendances suivantes à pom.xml .

 <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> 

Note du traducteur - pour java de plus de 9 ans, vous devez également ajouter les dépendances suivantes:

 <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> 

Les utilisateurs Gradle peuvent ajouter les dépendances suivantes au fichier 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") 

oĂč

  • Spring Boot Starter Security - implĂ©mente Spring Security
  • Spring Security OAuth2 - implĂ©mente les structures OAUTH2 pour le fonctionnement du serveur d'autorisation et du serveur de ressources.
  • Spring Security JWT - GĂ©nĂšre des jetons JWT
  • Spring Boot Starter JDBC - accĂšs Ă  la base de donnĂ©es pour la vĂ©rification des utilisateurs.
  • Spring Boot Starter Web - Fournit des points de terminaison HTTP.
  • Base de donnĂ©es H2 - stocke les informations utilisateur pour l'authentification et l'autorisation.

Le fichier pom.xml complet pom.xml illustré ci-dessous.

 <?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") } 

Maintenant, ajoutez les annotations @EnableAuthorizationServer et @EnableResourceServer au fichier d'application Spring Boot principal pour que l'application fonctionne Ă  la fois comme serveur d'autorisation et serveur de ressources.

Ajoutez également un simple point de terminaison HTTP (/ produits) pour accéder à l'API protégée par Spring Security à l'aide d'un jeton JWT.

 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"; } } 

Définissez une classe POJO pour stocker les informations d'authentification des utilisateurs.

 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; } } 

Ensuite, pour l'authentification, ajoutez la classe CustomUser, qui étend 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()); } } 

Créez une @Repository- pour récupérer les informations utilisateur de la base de données et ajoutez les privilÚges ROLE_SYSTEMADMIN. Cette classe sera également utilisée dans 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; } } 

Pour appeler le référentiel DAO, vous pouvez créer votre UserDetailsService , héritant de org.springframework.security.core.userdetails.UserDetailsService , comme illustré ci-dessous.

 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"); } } } 

Ensuite, créez une @onfiguration- pour activer Web Security . Définissez les paramÚtres de chiffrement du mot de passe ( BCryptPasswordEncoder ) et le bean AuthenticationManager qu'il BCryptPasswordEncoder .
Cette classe SecurityConfiguration doit hériter de la classe WebSecurityConfigurerAdapter .

 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(); } } 

Ajoutez maintenant une classe pour configurer OAuth2. Dans celui-ci, définissez l'ID client, le secret client, JwtAccessTokenConverter, les clés privées et publiques pour signer et vérifier le jeton, et configurer ClientDetailsServiceConfigurer pour des portées de jeton valides.

 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); } } 

Créez maintenant les clés privées et publiques en utilisant openssl .
Pour générer une clé privée, vous pouvez utiliser les commandes suivantes -

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

Pour clé publique -

 openssl rsa -in jwt.pem -pubout 

Pour Spring Boot antérieur à la version 1.5, ajoutez la propriété suivante au fichier application.properties (pour déterminer l'ordre de filtrage des ressources OAuth2).

 security.oauth2.resource.filter-order=3 

Si vous utilisez un fichier YAML, ajoutez ce qui suit.

 security: oauth2: resource: filter-order: 3 

Créez maintenant les data.sql schema.sql et data.sql dans le data.sql schema.sql aux schema.sql du schema.sql src/main/resources/directory pour connecter l'application à la base de données H2.

Le fichier schema.sql ressemble Ă  ceci:

 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'); 

Remarque - Le mot de passe dans la table de base de donnĂ©es doit ĂȘtre stockĂ© au format Bcrypt Encoder.
Vous pouvez créer un fichier JAR exécutable et exécuter l'application Spring Boot à l'aide des commandes Maven ou Gradle suivantes.


Pour Maven, vous pouvez utiliser la commande ci-dessous -

 mvn clean install 

AprÚs «BUILD SUCCESS», vous pouvez trouver les fichiers JAR dans le répertoire target .

Pour Gradle, vous pouvez utiliser la commande -

 gradle clean build 

AprÚs «BUILD SUCCESSFUL», vous pouvez trouver les fichiers JAR dans le répertoire build/libs .
Exécutez maintenant le fichier JAR avec la commande -

java –jar < JARFILE >

L'application lancée dans Tomcat sur le port 8080.



Envoyez maintenant une demande POST via POSTMAN pour recevoir un jeton OAUTH2.

http://localhost:8080/oauth/token
Ajoutez maintenant les en-tĂȘtes de demande -

  • Autorisation - Basique avec votre identifiant client et votre secret client.
  • Type de contenu - application / x-www-form-urlencoded



Et demander des paramĂštres -

  • grant_type = mot de passe
  • nom d'utilisateur = votre nom
  • mot de passe = votre mot de passe



Maintenant, exécutez et obtenez access_token comme indiqué.



CrĂ©ez maintenant une demande Ă  l'API du serveur de ressources avec un jeton Bearer dans l'en-tĂȘte.



Nous obtenons le résultat comme indiqué ci-dessous.



Nous attendons vos commentaires, et nous vous informons également que jusqu'au 31 mai vous pouvez rejoindre le cours à un prix spécial.

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


All Articles