今回は、OIDCについて簡単に見ていきたいと思います。
OIDCとは
- OIDCは「OpenID Connect」の略称で、認証のための開放型の標準プロトコルです。
- OAuth 2.0プロトコルの上に構築された身元認証レイヤーです。
- ウェブベースのアプリケーション、モバイルアプリ、JavaScript クライアントに、セキュアで相互運用可能な認証方法を提供します。
- ID トークンという概念を使用します。
- JSONウェブトークン(JWT)形式でエンコードされた情報を含みます。
主な特徴
- シングルサインオン(SSO)の実現
- セキュアなAPI認証
- クレーム(ユーザー情報)の標準化された交換
メリット
- 実装が比較的容易
- 広く採用されている標準規格
- セキュリティとプライバシーの向上
用途
- 企業の社内システム認証
- ソーシャルログイン(Google、Facebook等との連携)
- クラウドサービスの認証
OIDCは現代のウェブアプリケーションやサービスにおいて、セキュアで効率的な認証を実現するために広く使用されています。
サンプル
サンプルコードはReact、Javap+Springです。サンプルのため、全てのプロジェクト構造は含まれていません。また、コードサンプルはSpring BootバックエンドとReactフロントエンドを使用したOIDC認証の基本的な実装となります。
Java
- Spring Security と OAuth2 Clientを使用してOIDC認証を設定します。
- GoogleをOIDCプロバイダとして設定しています(他のプロバイダも同様に設定可能)。
- 認証されたユーザー情報を取得するためのエンドポイント(
/user)を提供します。
build.gradle
必要な依存関係をGradleファイルに追加します。
plugins {
id 'org.springframework.boot' version '2.6.3'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
implementation 'org.springframework.boot:spring-boot-starter-security'
// 必要に応じて、以下の依存関係を追加できます
// implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
useJUnitPlatform()
}
spring-boot-starter-web: Web- アプリケーション開発に必要な依存関係
spring-boot-starter-oauth2-client- OAuth2/OIDC クライアント機能を提供
spring-boot-starter-security- Spring Security 機能を提供
SecurityConfig
SecurityConfigクラスでOAuth2ログインを設定します。
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserService;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Value("${spring.security.oauth2.client.registration.google.client-id}")
private String googleClientId;
@Value("${spring.application.name}")
private String appName;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeRequests(a -> a
.antMatchers("/", "/error", "/webjars/**").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(oauth2 -> oauth2
.userInfoEndpoint(userInfo -> userInfo
.oidcUserService(this.oidcUserService())
)
)
.logout(l -> l
.logoutSuccessUrl("/")
.permitAll()
);
return http.build();
}
@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
OidcUser oidcUser = delegate.loadUser(userRequest);
// ここでユーザー情報を処理したり、カスタムクレームを追加したりできます
return oidcUser;
};
}
}
.oauth2Login(oauth2 -> ...)
- これは OAuth 2.0 / OIDC ログインを有効にするメソッドです。
- ラムダ式を使用して、OAuth 2.0 ログインの詳細な設定を行います。
oauth2.userInfoEndpoint(userInfo -> ...)
userInfoEndpoint()は、認証後にユーザー情報を取得するエンドポイントの設定を行います。- OIDC プロバイダ(例:Google)のユーザー情報エンドポイントからデータを取得する方法を指定します。
userInfo.oidcUserService(this.oidcUserService())
oidcUserService()は、OIDC プロバイダから取得したユーザー情報を処理するサービスを指定します。this.oidcUserService()は、この設定クラス
Controller
UserControllerでユーザー情報を提供するエンドポイントを実装します。
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.Map;
@RestController
public class UserController {
@GetMapping("/user")
public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
return Collections.singletonMap("name", principal.getAttribute("name"));
}
}
application.yml
application.ymlにGoogleのクライアントIDとシークレットを設定します(環境変数を使用)。
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
React
- ユーザーの認証状態に基づいて、ログインボタンまたはウェルカムメッセージを表示します。
- バックエンドの
「/user」エンドポイントを呼び出してユーザー情報を取得します。 - ログイン処理はバックエンドにリダイレクトすることで行います。
App.js
function App() {
const [user, setUser] = useState(null);
useEffect(() => {
axios.get('/user')
.then(response => setUser(response.data))
.catch(error => console.error('Error fetching user', error));
}, []);
const login = () => {
window.location.href = '/oauth2/authorization/google';
};
const logout = () => {
axios.post('/logout')
.then(() => setUser(null))
.catch(error => console.error('Error logging out', error));
};
if (!user) {
return <button onClick={login}>Login with Google</button>;
}
return (
<div>
<h1>Welcome, {user.name}!</h1>
<button onClick={logout}>Logout</button>
</div>
);
}
package.json
{
"name": "oidc-react-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"axios": "^0.24.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
},
"proxy": "http://localhost:8080"
}
- Reactアプリケーションを作成し、必要な依存関係(axios等)をインストールします。
App.jsで認証状態の管理とユーザー情報の取得ロジックを実装します。- プロキシ設定を
package.jsonに追加し、APIリクエストをバックエンドに転送します。
