1. Introduction
In this post, I would demo an example of spring cloud(Spring Boot and Spring Security) and oauth2 authorization server, And I would use postman to test it.
2. Environment
JDK 1.8
Spring Cloud Greenwich.RELEASE
3. Example
3.1 The 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" >
<parent>
<artifactId> ttt</artifactId>
<groupId> com.zzz</groupId>
<version> 1.0-SNAPSHOT</version>
</parent>
<modelVersion> 4.0.0</modelVersion>
<artifactId> oauth-authz-server</artifactId>
<properties>
<java.version> 1.8</java.version>
<spring-cloud.version> Greenwich.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId> org.springframework.security.oauth.boot</groupId>
<artifactId> spring-security-oauth2-autoconfigure</artifactId>
<version> 2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId> org.springframework.cloud</groupId>
<artifactId> spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId> org.projectlombok</groupId>
<artifactId> lombok</artifactId>
<version> 1.18.8</version>
<scope> provided</scope>
</dependency>
<dependency>
<groupId> org.springframework.boot</groupId>
<artifactId> spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId> org.springframework.cloud</groupId>
<artifactId> spring-cloud-starter-parent</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>
<plugin>
<groupId> org.apache.maven.plugins</groupId>
<artifactId> maven-compiler-plugin</artifactId>
<version> 3.5.1</version>
<configuration>
<source> 1.8</source>
<target> 1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
3.2 The application.properties
server.port=8901
server.servlet.context-path=/auth
3.3 The main class
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 ;
/**
* Created on 2019/8/27.
*/
@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
public class Oauth2AuthzServerApplication {
public static void main ( String [] args ) {
SpringApplication . run ( Oauth2AuthzServerApplication . class , args );
}
}
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 ;
/**
* Created on 2019/8/27.
*/
@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 ( "{noop}password1" ). roles ( "USER" )
. and ()
. withUser ( "william.woodward" ). password ( "{noop}password2" ). roles ( "USER" , "ADMIN" );
}
}
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 ;
/**
* Created on 2019/8/27.
*/
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager ;
@Autowired
private UserDetailsService userDetailService ;
@Override
public void configure ( ClientDetailsServiceConfigurer clients ) throws Exception {
clients . inMemory (). withClient ( "service1" )
. secret ( "{noop}thisissecret" )
. authorizedGrantTypes ( "refresh_token" , "password" , "client_credentials" )
. scopes ( "webclient" , "mobileclient" );
}
@Override
public void configure ( AuthorizationServerEndpointsConfigurer endpoints ) throws Exception {
endpoints . authenticationManager ( authenticationManager )
. userDetailsService ( userDetailService );
}
}
4. Test by postman
4.1 The test url
The url should be: http://localhost:8901/auth/oauth/token, the method should be POST.
You can set the authorization header like this:
Spring cloud security expect you to send oauth params by a post form like this:
4.4 The response
After click send , we get this response:
5. The Exceptions
If we get this exception:
2019-08-27 19:50:31.415 ERROR 28564 --- [nio-8901-exec-6] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [/auth] threw exception
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:244) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$LazyPasswordEncoder.matches(WebSecurityConfigurerAdapter.java:594) ~[spring-security-config-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:90) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:166) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:175) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
Just pay attention to the secret and password settings:
You should set secret like this:
. secret ( "{noop}thisissecret" )
You should set password like this:
. withUser ( "john.carnell" ). password ( "{noop}password1" ). roles ( "USER" )
Pay attention to the {noop}.It would let spring store the password as text, otherwise it would be encoded.
6. Summary
It’s very easy to implement an authorization server of OAuth 2.0 with Spring Cloud and Spring Security!