Set up a Spring Boot web application that authenticates users through Alibaba Cloud Resource Access Management (RAM) using OAuth 2.0 and Spring Security.
Prerequisites
Before you begin, ensure that you have:
An Alibaba Cloud OAuth application. For more information, see Manage an OAuth application
A Spring Boot project initialized with Maven
Java Development Kit (JDK) 1.8 or later
Step 1: Add Maven dependencies
Add the following dependencies to the pom.xml file of your Spring Boot project.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- OAuth 2.0 client for login flow -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- OAuth 2.0 resource server for token validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Web framework -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Test support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Frontend libraries -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>js-cookie</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>Run mvn install to download the dependencies.
Step 2: Configure the OAuth 2.0 provider
Create application.yml (or application.yaml) in the src/main/resources directory. This file registers Alibaba Cloud as an OAuth 2.0 provider and configures the client credentials.
spring:
security:
oauth2:
client:
registration:
alibabacloud:
client-id: <your-client-id>
client-secret: <your-client-secret>
client-authentication-method: client_secret_basic
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
client-name: alibabacloud
provider:
alibabacloud:
authorization-uri: https://signin.alibabacloud.com/oauth2/v1/auth
token-uri: https://oauth.alibabacloud.com/v1/token
user-info-uri: https://oauth.alibabacloud.com/v1/userinfo
user-name-attribute: sub
jwk-set-uri: https://oauth.alibabacloud.com/v1/keysReplace the following placeholders with your actual values:
| Placeholder | Description | Where to find it |
|---|---|---|
<your-client-id> | The application ID of your OAuth application | RAM console > Integrations > OAuth (Preview) > your application |
<your-client-secret> | The application secret of your OAuth application | RAM console > Integrations > OAuth (Preview) > your application > Application Secret tab > Create Secret |
The following table describes the provider configuration parameters:
| Parameter | Value | Description |
|---|---|---|
authorization-uri | https://signin.alibabacloud.com/oauth2/v1/auth | The authorization endpoint where users are redirected to log on |
token-uri | https://oauth.alibabacloud.com/v1/token | The endpoint that exchanges the authorization code for an access token |
user-info-uri | https://oauth.alibabacloud.com/v1/userinfo | The endpoint that retrieves the authenticated user's profile |
user-name-attribute | sub | The claim in the user info response used as the username (subject identifier) |
jwk-set-uri | https://oauth.alibabacloud.com/v1/keys | The JSON Web Key (JWK) set endpoint for verifying token signatures |
Step 3: Write the backend security configuration
Create the WebApplication class that configures Spring Security with OAuth 2.0 logon, cross-site request forgery (CSRF) protection, and access control.
Save this file as WebApplication.java in your project's main source package.
import org.springframework.boot.SpringApplication;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.web.authentication.AuthenticationEntryPointFailureHandler;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Map;
public class WebApplication extends WebSecurityConfigurerAdapter {
private AuthenticationEntryPointFailureHandler handler = new AuthenticationEntryPointFailureHandler((request, response, authException) -> response.sendError(401, "Unauthorized"));
@GetMapping("/user")
public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
return Collections.singletonMap("name", principal.getAttribute("name"));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(a -> a
.antMatchers("/", "/error", "/webjars/**").permitAll()
.anyRequest().authenticated()
)
.exceptionHandling(e -> e
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
)
.oauth2Login(o -> o
.failureHandler((request, response, exception) -> {
request.getSession().setAttribute("error.message", exception.getMessage());
handler.onAuthenticationFailure(request, response, exception);
})
)
.logout(l -> l
.logoutSuccessUrl("/").permitAll()
)
.csrf(c -> c
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);
}
@GetMapping("/error")
public String error(HttpServletRequest request) {
String message = (String) request.getSession().getAttribute("error.message");
if (message != null) {
request.getSession().removeAttribute("error.message");
}
return message;
}
}The class handles the following:
| Component | Behavior |
|---|---|
| Access control | /, /error, and /webjars/** allow anonymous access. All other paths require authentication. |
| OAuth 2.0 logon | Unauthenticated requests to protected paths redirect to the Alibaba Cloud logon page. After successful authentication, the user is redirected back to the application. |
| Failure handling | Authentication failures store the error message in the session and return HTTP 401. |
| Logout | Redirects the user to /. |
| CSRF protection | Uses CookieCsrfTokenRepository with HttpOnly disabled, so frontend JavaScript can read the CSRF token. |
/user endpoint | Returns the authenticated user's name from OAuth 2.0 user attributes. |
/error endpoint | Returns the most recent error message from the session and clears it. |
Step 4: Create the frontend page
Create index.html in the src/main/resources/static directory.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>Demo</title>
<meta name="description" content=""/>
<meta name="viewport" content="width=device-width"/>
<base href="/"/>
<link rel="stylesheet" href="/webjars/bootstrap/css/bootstrap.min.css"/>
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/bootstrap/js/bootstrap.min.js"></script>
<script src="/webjars/js-cookie/js.cookie.js">
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (settings.type === 'POST' || settings.type === 'PUT' || settings.type === 'DELETE') {
if (!(/^(http:\/\/|https:\/\/)/.test(settings.url))) {
xhr.setRequestHeader("X-XSRF-TOKEN", Cookies.get('XSRF-TOKEN'));
}
}
}
});
</script>
</head>
<body>
<h1>Demo</h1>
<div class="container text-danger error"></div>
<script>
$.get("/error", function (data) {
if (data) {
$(".error").html(data);
} else {
$(".error").html('');
}
});
</script>
<div class="container unauthenticated">
With Aliyun: <a href="/oauth2/authorization/aliyun">click here</a>
</div>
<div class="container authenticated">
With Google: <a href="/oauth2/authorization/google">click here</a>
</div>
<script type="text/javascript">
$.get("/user", function(data) {
$("#user").html(data.name);
$(".unauthenticated").hide()
$(".authenticated").show()
});
</script>
<div class="container authenticated">
Logged in as: <span id="user"></span>
<div>
<button onClick="logout()" class="btn btn-primary">Logout</button>
</div>
</div>
<script type="text/javascript">
var logout = function() {
$.post("/logout", function() {
$("#user").html('');
$(".unauthenticated").show();
$(".authenticated").hide();
})
return true;
}
</script>
</body>
</html>Before authentication, the page displays a logon link. After a user logs on through Alibaba Cloud OAuth, the page shows the user's name and a Logout button. CSRF tokens are attached automatically to POST, PUT, and DELETE requests through the X-XSRF-TOKEN header.
Step 5: Verify the integration
Start the Spring Boot application:
mvn spring-boot:runOpen
http://localhost:8080in a browser. The page shows an Alibaba Cloud logon link.Click the logon link. The browser redirects to the Alibaba Cloud logon page.
Log on with your Alibaba Cloud account. After successful authentication, the browser redirects back to the application and displays your username.
Click Logout to end the session. The page returns to the initial logon state.