J'essaie d'implémenter un serveur d'authentification utilisant Spring Boot, Spring Cloud Security et Spring Cloud oauth2.
Je reçois une erreur ci-dessous lorsque j'essaie de frapper http: // localhost: 8080/auth/oauth/token de postman
{ "erreur": "non autorisé", "error_description": "Une authentification complète est requise pour accéder à cette ressource" }
Ci-dessous mon pom.xml
<?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.teckink.tp</groupId>
<artifactId>tp-auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>tp-auth-server</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.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>
<spring-cloud.version>Finchley.M9</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
Classe Débutant:
package com.teckink.tp.authserver;
import Java.util.HashMap;
import Java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
@EnableResourceServer
@EnableAuthorizationServer
public class App {
@RequestMapping(value = { "/user" }, produces = "application/json")
public Map<String, Object> user(OAuth2Authentication user) {
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("user", user.getUserAuthentication().getPrincipal());
userInfo.put("authorities", AuthorityUtils.authorityListToSet(user.getUserAuthentication().getAuthorities()));
return userInfo;
}
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Classe OAuth2Config qui définit le client et son secret:
package com.teckink.tp.authserver.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
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;
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("eagleeye")
.secret("thisissecret")
.authorizedGrantTypes("refresh_token", "password", "client_credentials")
.scopes("webclient", "mobileclient");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
Classe WebSecurityConfigurer qui définit un utilisateur, un mot de passe et des rôles en mémoire:
package com.teckink.tp.authserver.security;
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.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
@Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("john.carnell").password("password1").roles("USER")
.and()
.withUser("william.woodward").password("password2").roles("USER", "ADMIN");
}
}
J'appelle Rest API de POSTMAN comme ci-dessous - La demande avec l'écran d'authentification s'affiche comme ci-dessous:
Lorsque vous exécutez votre exemple d’application, l’exception suivante apparaît.
Java.lang.IllegalArgumentException: aucun PasswordEncoder mappé pour l'id "null"
Dans spring-security-core: 5.0, PasswordEncoder par défaut est créé en tant que DelegatingPasswordEncoder. Par conséquent, lorsque vous stockez les utilisateurs en mémoire, vous fournissez les mots de passe en texte brut, puis lorsque vous essayez de récupérer l'encodeur à partir de DelegatingPasswordEncoder pour valider le mot de passe, il ne peut pas en trouver.
Plus de détails dans ce lien Encodage du mot de passe
Pour remédier à cela, pour une implémentation en production, vous devez activer une instance de BCryptPasswordEncoder
Pour le développement, vous pouvez essayer les modifications suivantes afin de remplacer le codage du mot de passe en ajoutant {noop}
à la valeur du mot de passe. Cela traitera le mot de passe en activant la NoOpPasswordEncoder
au lieu de la valeur par défaut DelegatingPasswordEncoder
et traitera votre mot de passe en tant que texte brut.
Classe OAuth2Config
clients.inMemory()
.withClient("eagleeye")
.secret("{noop}thisissecret")
.authorizedGrantTypes("refresh_token", "password", "client_credentials")
.scopes("webclient", "mobileclient");
Classe WebSecurityConfigurer
auth
.inMemoryAuthentication()
.withUser("john.carnell"). password("{noop}password1").roles("USER")
.and()
.withUser("william.woodward").password("{noop}password2").roles("USER", "ADMIN");
Maintenant, lorsque vous essayez de Postman, vous pouvez générer un jeton
MODIFIER
Projet Github avec une démo de travail ici
J'ai remarqué que votre type de subvention est répertorié comme "mot de passe" et non "mot de passe" dans votre message.
C'est bizarre, la même chose s'est passée ici. Je l'ai résolu en utilisant la commande curl.
curl -v -X POST http://url:8080/api/oauth/token -u "yourclientid:yourclient_secret" -d "grant_type=password" -d "username=yourusername" -d "password=yourpassword"
Ou Si vous le voulez dans postman, allez dans Autorisation -> sélectionnez le type OAUTH2 -> Obtenir un jeton d'accès entrez la description de l'image ici