Master OAuth2 with Spring Cloud Security: Step‑by‑Step Guide
This article introduces Spring Cloud Security and demonstrates how to integrate OAuth2 for single sign‑on, token relay, and token exchange in a Spring Boot application, covering OAuth2 concepts, authorization flows, module setup, configuration, and practical usage of authorization‑code and password grant types with code examples.
Spring Cloud Security provides a set of solutions for building secure Spring Boot applications; combined with OAuth2 it enables single sign‑on, token relay, token exchange, and other features.
OAuth2 Introduction
OAuth 2.0 is an industry‑standard protocol for authorization. It defines specific grant flows to simplify client development for web, desktop, and mobile applications.
OAuth2 Terminology
Resource Owner: the end user who owns the protected resource and has an account.
Resource Server: the server that hosts the protected resources and serves them when a valid access token is presented.
Client: the application that accesses resources on behalf of the user, using an access token; it can be a browser, mobile app, or server.
Authorization Server: the server that authenticates users and issues tokens to clients after successful authentication.
Four Grant Types
Authorization Code: the standard OAuth2 flow where the client redirects the user to the authorization server, obtains an authorization code, and exchanges it for an access token.
Implicit: a simplified flow that skips the authorization code step and returns an access token directly.
Resource Owner Password Credentials: the client directly collects the user's username and password and exchanges them for an access token.
Client Credentials: the client authenticates itself (e.g., with client_id and client_secret) to obtain an access token.
Two Common Grant Types
Authorization Code Grant
(A) Client redirects the user to the authorization server.
(B) User logs in and grants authorization on the authorization server.
(C) Authorization server returns an authorization code to the client.
(D) Client exchanges the authorization code (and redirect URI) for an access token.
(E) Authorization server issues the access token (optionally with a refresh token).
Password Grant
(A) Client collects the username and password from the user.
(B) Client sends the credentials to the authorization server.
(C) Authorization server returns an access token (optionally with a refresh token).
Using OAuth2
Creating oauth2-server Module
We create an oauth2-server module to act as the authorization server.
Add the following dependencies to pom.xml:
<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-web</artifactId>
</dependency>Configure application.yml:
server:
port: 9401
spring:
application:
name: oauth2-serviceImplement UserService that implements UserDetailsService to load user information:
@Service
public class UserService implements UserDetailsService {
private List<User> userList;
@Autowired
private PasswordEncoder passwordEncoder;
@PostConstruct
public void initData() {
String password = passwordEncoder.encode("123456");
userList = new ArrayList<>();
userList.add(new User("macro", password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin")));
userList.add(new User("andy", password, AuthorityUtils.commaSeparatedStringToAuthorityList("client")));
userList.add(new User("mark", password, AuthorityUtils.commaSeparatedStringToAuthorityList("client")));
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<User> findUserList = userList.stream()
.filter(user -> user.getUsername().equals(username))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(findUserList)) {
return findUserList.get(0);
} else {
throw new UsernameNotFoundException("用户名或密码错误");
}
}
}Add the authorization server configuration with @EnableAuthorizationServer:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserService userService;
// Configure password grant
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.authenticationManager(authenticationManager)
.userDetailsService(userService);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("admin") // client_id
.secret(passwordEncoder.encode("admin123456")) // client_secret
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(864000)
.redirectUris("http://www.baidu.com")
.scopes("all")
.authorizedGrantTypes("authorization_code", "password");
}
}Add the resource server configuration with @EnableResourceServer:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.requestMatchers()
.antMatchers("/user/**"); // protected resource paths
}
}Configure Spring Security to allow authentication endpoints and form login:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}Add a test controller to verify authentication:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/getCurrentUser")
public Object getCurrentUser(Authentication authentication) {
return authentication.getPrincipal();
}
}Authorization Code Grant Usage
Start the oauth2-server service.
In a browser, visit the authorization URL:
http://localhost:9401/oauth/authorize?response_type=code&client_id=admin&redirect_uri=http://www.baidu.com&scope=all&state=normalEnter username and password to log in.
After login, grant authorization.
The browser redirects to the configured redirect URI with an authorization code: https://www.baidu.com/?code=eTsADY&state=normal Exchange the code for an access token by sending a POST request to http://localhost:9401/oauth/token with Basic authentication (client_id and client_secret) and the required body parameters.
Use the obtained access token in the Authorization header to call the protected endpoint http://localhost:9401/user/getCurrentUser, which now succeeds.
Password Grant Usage
Send a POST request to http://localhost:9401/oauth/token using Basic authentication (client_id and client_secret).
Include the username and password in the request body to obtain an access token.
Modules Used
springcloud-learning
└── oauth2-server -- OAuth2 authentication test serviceProject Source Code
https://github.com/macrozheng/springcloud-learning
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
