このドキュメントでは、OAuth 2.0 と Spring Security を使用して、Alibaba Cloud Resource Access Management (RAM) 経由でユーザーを認証する Spring Boot Web アプリケーションをセットアップする方法について説明します。
前提条件
開始する前に、以下が準備できていることを確認してください:
Alibaba Cloud OAuth アプリケーション。詳細については、「OAuth アプリケーションの管理」をご参照ください。
Maven で初期化された Spring Boot プロジェクト
Java 開発キット (JDK) 1.8 以降
ステップ 1: Maven 依存関係の追加
ご利用の Spring Boot プロジェクトの pom.xml ファイルに、次の依存関係を追加します。
<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 クライアント -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!-- トークン検証用の OAuth 2.0 リソースサーバー -->
<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 フレームワーク -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- テストサポート -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- フロントエンドライブラリ -->
<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>mvn install を実行して、依存関係をダウンロードします。
ステップ 2: OAuth 2.0 プロバイダーの設定
src/main/resources ディレクトリに application.yml (または application.yaml) を作成します。このファイルは、Alibaba Cloud を OAuth 2.0 プロバイダーとして登録し、クライアント認証情報を設定します。
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/keys次のプレースホルダーを実際の値に置き換えてください:
| プレースホルダー | 説明 | 確認方法 |
|---|---|---|
<your-client-id> | OAuth アプリケーションのアプリケーション ID | RAM コンソール > 統合 > OAuth (プレビュー) > ご利用のアプリケーション |
<your-client-secret> | OAuth アプリケーションのアプリケーション シークレット | RAM コンソール > 統合 > OAuth (プレビュー) > ご利用のアプリケーション > アプリケーション シークレット タブ > シークレットの作成 |
次の表に、プロバイダー設定パラメーターを示します:
| パラメーター | 値 | 説明 |
|---|---|---|
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/keys | トークン署名を検証するための JSON Web Key (JWK) セットエンドポイント |
ステップ 3: バックエンドセキュリティ構成の作成
OAuth 2.0 ログイン、クロスサイトリクエストフォージェリ (CSRF) 保護、およびアクセスの制御を使用して Spring Security を設定する WebApplication クラスを作成します。
このファイルを、プロジェクトのメインソースパッケージに WebApplication.java として保存します。
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;
}
}このクラスは、以下を処理します:
| コンポーネント | 動作 |
|---|---|
| アクセスの制御 | /、/error、および /webjars/** は匿名アクセスを許可します。他のすべてのパスには認証が必要です。 |
| OAuth 2.0 ログイン | 保護されたパスへの未認証のリクエストは、Alibaba Cloud のログインページにリダイレクトされます。認証が成功すると、ユーザーはアプリケーションにリダイレクトされます。 |
| 障害処理 | 認証に失敗すると、エラーメッセージがセッションに保存され、HTTP 401 が返されます。 |
| ログアウト | ユーザーを / にリダイレクトします。 |
| CSRF 保護 | CookieCsrfTokenRepository を HttpOnly を無効にして使用するため、フロントエンドの JavaScript が CSRF トークンを読み取ることができます。 |
/user エンドポイント | OAuth 2.0 のユーザー属性から認証済みユーザーの名前を返します。 |
/error エンドポイント | セッションから最新のエラーメッセージを返し、それをクリアします。 |
ステップ 4: フロントエンドページの作成
src/main/resources/static ディレクトリに index.html を作成します。
<!DOCTYPE html>
<html lang="ja-JP">
<head>
<meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>デモ</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>デモ</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">
Aliyun を使用: <a href="/oauth2/authorization/aliyun">ここをクリック</a>
</div>
<div class="container authenticated">
Google を使用: <a href="/oauth2/authorization/google">ここをクリック</a>
</div>
<script type="text/javascript">
$.get("/user", function(data) {
$("#user").html(data.name);
$(".unauthenticated").hide()
$(".authenticated").show()
});
</script>
<div class="container authenticated">
ログイン中:
<div>
<button onClick="logout()" class="btn btn-primary">ログアウト</button>
</div>
</div>
<script type="text/javascript">
var logout = function() {
$.post("/logout", function() {
$("#user").html('');
$(".unauthenticated").show();
$(".authenticated").hide();
})
return true;
}
</script>
</body>
</html>認証前、ページにはログインリンクが表示されます。ユーザーが Alibaba Cloud OAuth を介してログインすると、ページにユーザー名と [ログアウト] ボタンが表示されます。CSRF トークンは、X-XSRF-TOKEN ヘッダーを介して POST、PUT、および DELETE リクエストに自動的にアタッチされます。
ステップ 5: 統合の検証
Spring Boot アプリケーションを起動します:
mvn spring-boot:runブラウザで
http://localhost:8080を開きます。ページに Alibaba Cloud のログインリンクが表示されます。ログインリンクをクリックします。ブラウザが Alibaba Cloud のログインページにリダイレクトされます。
ご利用の Alibaba Cloud アカウントでログインします。認証が成功すると、ブラウザはアプリケーションにリダイレクトされ、ご利用のユーザー名が表示されます。
[ログアウト] をクリックしてセッションを終了します。ページは初期のログイン状態に戻ります。