Protect Service with Spring Security and OAuth2 - wuyichen24/spring-microservices-in-action GitHub Wiki
Overview
For protecting your services with Spring Security and OAuth2, you need to do several things
Configure the authentication service
Set dependencies
dependencies {
// Spring Security and OAuth2
compile group: 'org.springframework.cloud', name: 'spring-cloud-security'
compile group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.1.3.RELEASE'
// For storing credentials and roles in database
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '1.5.0.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-autoconfigure', version: '1.5.0.RELEASE'
compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.38'
}
Change the application configuration
After Spring Boot 1.5, the order of the OAuth2 resource filter has been changed. So you need to restore it to the original default value. Otherwise when you hit the URL: http://localhost:8901/auth/user
to retrieve the user information, it will return a login page rather than the user information in JSON.
security:
oauth2:
resource:
filter-order: 3
Set the client application's credential
For storing client application's credential, it can be stored in
Store in memory
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // Define what client applications are registered with the service
clients.inMemory() // Store the application information in memory
.withClient("eagleeye") // Specify which client application will register
.secret("thisissecret") // Specify the secret which will be used to get the access token
.authorizedGrantTypes("refresh_token", "password", "client_credentials") // Provide a list of the authorization grant types that will be supported by the service
.scopes("webclient", "mobileclient"); // Define the types of the client applications can get the access token from the service
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
Store in database
See Store Clients and Users' Credentials to DB
Set the client users' credentials and roles
For storing client users' credentials and roles, it can be stored in
Store in memory
@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") // Define the first user: john.carnell with the password "password1" and the role "USER"
.and()
.withUser("william.woodward").password("password2").roles("USER", "ADMIN"); // Define the second user: william.woodward with the password "password2" and the role "ADMIN"
}
}
Store in database
See Store Clients and Users' Credentials to DB
Store in LDAP server
(Need to do)
Generate the access token
We will hit the endpoint of the authentication service to get the access token.
-
Method: POST
-
Authentication
- Type: Basic Auth
- Username: eagleeye
- Password: thisissecret
-
Body:
Key Value grant_type password scope webclient username john.carnell password password1
After sending the HTTP request to the authentication service with the credential, it will return the access token:
{
"access_token": "945ab1d3-beec-4e57-839b-bee7ef2cb167",
"token_type": "bearer",
"refresh_token": "fca36d96-debb-430d-a7d1-adcffe512034",
"expires_in": 43199,
"scope": "webclient"
}
The value 945ab1d3-beec-4e57-839b-bee7ef2cb167
is the access token.
Configure the protected service
In this example, we will use the organization service as a protected service.
Set dependencies
dependencies {
// Spring Security and OAuth2
compile group: 'org.springframework.cloud', name: 'spring-cloud-security'
compile group: 'org.springframework.security.oauth', name: 'spring-security-oauth2', version: '2.1.3.RELEASE'
}
Change the application configuration
You need to let the protected service know where is the authentication service which can validate the OAuth2 access token.
security:
oauth2:
resource:
userInfoUri: http://localhost:8901/auth/user # This is the URL to validate the access token
Add the annotation to the bootstrap class
@EnableResourceServer // Enable this service as the protected resource by OAuth2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Define permissions
You can give permissions to:
Give permissions to all authenticated users
ResourceServerConfiguration.java
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
Give permissions to a group of users with a certain role
ResourceServerConfiguration.java
@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.antMatchers(HttpMethod.DELETE, "/v1/organizations/**")
.hasRole("ADMIN") // Only ADMIN role have the permission to do DELETE operations
.anyRequest()
.authenticated();
}
}
Verify: Send the HTTP request to the protected service with the access token
After setting up the protected service, when you sent a HTTP request to that protected service, the header of the request should contain the access token.
- URL: http://localhost:8060/v1/organizations/e254f8c-c442-4ebe-a82a-e2fc1d1ff78a
- Method: GET
- Headers:
Key | Value |
---|---|
Authorization | Bearer 945ab1d3-beec-4e57-839b-bee7ef2cb167 |
(You may need to get a new access token for your case)