SpringSecurityOAuth2を使用したシンプルなシングルサインオン
1. 概要
このチュートリアルでは、 SSO –シングルサインオン– SpringセキュリティOAuthとSpring Bootを使用し、Keycloakを認証サーバーとして使用する方法について説明します。
4つの別々のアプリケーションを使用します。
- 承認サーバー–これは中央の認証メカニズムです
- リソースサーバー– Fooのプロバイダー
- 2つのクライアントアプリケーション–SSOを使用するアプリケーション
非常に簡単に言えば、ユーザーが1つのクライアントアプリを介してリソースにアクセスしようとすると、承認サーバーを介して最初に認証するようにリダイレクトされます。 Keycloakはユーザーにサインインし、最初のアプリにログインしたまま、同じブラウザーを使用して2番目のクライアントアプリにアクセスする場合、ユーザーは資格情報を再度入力する必要はありません。
認証の委任を駆動するために、OAuth2から認証コード付与タイプを使用します。
Springセキュリティ5でOAuthスタックを使用します。SpringセキュリティOAuthレガシースタックを使用する場合は、次の前の記事を参照してください:シンプルなシングルサインオンSpringセキュリティOAuth2(レガシースタック)
移行ガイドによると:
SpringSecurityはこの機能をOAuth2.0ログインと呼び、SpringSecurityOAuthはこれをSSOと呼びます。
さて、すぐに飛び込みましょう。
2. 承認サーバー
以前は、Spring Security OAuthスタックは、承認サーバーをSpringアプリケーションとしてセットアップする可能性を提供していました。
ただし、OAuthスタックはSpringによって非推奨になり、認証サーバーとしてKeycloakを使用するようになります。
今回は、Spring Bootアプリに組み込みKeycloakサーバーとして認証サーバーを設定します。
事前構成、では、クライアントアプリケーションごとに1つずつ、ssoClient-1と ssoClient-2、の2つのクライアントを定義します。
3. リソースサーバー
次に、リソースサーバー、またはクライアントアプリが消費するFooを提供するRESTAPIが必要です。
これは基本的に、以前のAngularクライアントアプリで使用したものと同じです。
4. クライアントアプリケーション
次に、Thymeleafクライアントアプリケーションを見てみましょう。 もちろん、構成を最小限に抑えるためにSpring Bootを使用します。
シングルサインオン機能を示すには、これらのうち2つが必要になることに注意してください。
4.1. Mavenの依存関係
まず、pom.xmlに次の依存関係が必要になります。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty</artifactId>
</dependency>
セキュリティを含む、必要なすべてのクライアントサポートを含めるには、spring-boot-starter-oauth2-clientを追加するだけです。 また、古い RestTemplate は非推奨になるため、 WebClient を使用します。そのため、 spring-webfluxとreactor-netty。
4.2. セキュリティ構成
次に、最も重要な部分は、最初のクライアントアプリケーションのセキュリティ構成です。
@EnableWebSecurity
public class UiSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/")
.permitAll()
.anyRequest()
.authenticated()
.and()
.oauth2Login();
}
@Bean
WebClient webClient(ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrationRepository,
authorizedClientRepository);
oauth2.setDefaultOAuth2AuthorizedClient(true);
return WebClient.builder().apply(oauth2.oauth2Configuration()).build();
}
}
この構成の中核部分はoauth2Login()メソッドであり、SpringSecurityのOAuth2.0ログインサポートを有効にするために使用されます。デフォルトでシングルサインオンソリューションであるKeycloakを使用しているためWebアプリとRESTfulWebサービスの場合、SSOの構成を追加する必要はありません。
最後に、 WebClient Beanを定義して、リソースサーバーに送信される要求を処理する単純なHTTPクライアントとして機能します。
そして、これがapplication.ymlです。
spring:
security:
oauth2:
client:
registration:
custom:
client-id: ssoClient-1
client-secret: ssoClientSecret-1
scope: read,write
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8082/ui-one/login/oauth2/code/custom
provider:
custom:
authorization-uri: http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/auth
token-uri: http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/token
user-info-uri: http://localhost:8083/auth/realms/baeldung/protocol/openid-connect/userinfo
user-name-attribute: preferred_username
thymeleaf:
cache: false
server:
port: 8082
servlet:
context-path: /ui-one
resourceserver:
api:
project:
url: http://localhost:8081/sso-resource-server/api/foos/
ここで、 spring.security.oauth2.client.registration は、クライアントを登録するためのルート名前空間です。 登録IDcustomでクライアントを定義しました。 次に、 client-id 、 client-secret 、 scope 、 authentication-grant-type 、redirect-uriを定義しました。 、もちろん、これは認証サーバー用に定義されたものと同じである必要があります。
その後、同じIDで custom を使用して、サービスプロバイダーまたは承認サーバーを定義し、Springセキュリティで使用するさまざまなURIを一覧表示しました。 定義する必要があるのはこれだけです。フレームワークは、Keycloakへのリダイレクトを含むログインプロセス全体をシームレスに実行します。
また、ここでの例では、承認サーバーをロールアウトしましたが、もちろん、FacebookやGitHubなどの他のサードパーティプロバイダーを使用することもできます。
4.3. コントローラー
次に、クライアントアプリにコントローラーを実装して、リソースサーバーからFooを要求します。
@Controller
public class FooClientController {
@Value("${resourceserver.api.url}")
private String fooApiUrl;
@Autowired
private WebClient webClient;
@GetMapping("/foos")
public String getFoos(Model model) {
List<FooModel> foos = this.webClient.get()
.uri(fooApiUrl)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<FooModel>>() {
})
.block();
model.addAttribute("foos", foos);
return "foos";
}
}
ご覧のとおり、ここではfoosテンプレートにリソースを提供するメソッドが1つだけあります。 ログイン用のコードを追加する必要はありませんでした。
4.4. フロントエンド
それでは、クライアントアプリケーションのフロントエンド構成を見てみましょう。 主にサイトですでに取り上げているため、ここではこれに焦点を当てません。
ここでのクライアントアプリケーションには、非常にシンプルなフロントエンドがあります。 これがindex.htmlです。
<a class="navbar-brand" th:href="@{/foos/}">Spring OAuth Client Thymeleaf - 1</a>
<label>Welcome !</label> <br /> <a th:href="@{/foos/}">Login</a>
そしてfoos.html:
<a class="navbar-brand" th:href="@{/foos/}">Spring OAuth Client Thymeleaf -1</a>
Hi, <span sec:authentication="name">preferred_username</span>
<h1>All Foos:</h1>
<table>
<thead>
<tr>
<td>ID</td>
<td>Name</td>
</tr>
</thead>
<tbody>
<tr th:if="${foos.empty}">
<td colspan="4">No foos</td>
</tr>
<tr th:each="foo : ${foos}">
<td><span th:text="${foo.id}"> ID </span></td>
<td><span th:text="${foo.name}"> Name </span></td>
</tr>
</tbody>
</table>
foos.html ページでは、ユーザーを認証する必要があります。 認証されていないユーザーがfoos.htmlにアクセスしようとすると、最初にKeycloakのログインページにリダイレクトされます。
4.5. 2番目のクライアントアプリケーション
別のclient_id ssoClient-2 を使用して、2番目のアプリケーションSpringOAuthクライアントThymeleaf-2を構成します。
これは、今説明した最初のアプリケーションとほとんど同じです。
application.yml は、spring.security.oauth2に異なるclient_id 、 client_secret 、およびredirect_uriを含むように異なります。 client.registration:
spring:
security:
oauth2:
client:
registration:
custom:
client-id: ssoClient-2
client-secret: ssoClientSecret-2
scope: read,write
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8084/ui-two/login/oauth2/code/custom
そしてもちろん、それらを並行して実行できるように、別のサーバーポートも必要です。
server:
port: 8084
servlet:
context-path: /ui-two
最後に、フロントエンドのHTMLを微調整して、タイトルを –1ではなくSpringOAuth Client Thymeleaf – 2 にして、2つを区別できるようにします。
5. SSOの動作のテスト
SSOの動作をテストするために、アプリケーションを実行してみましょう。
このためには、4つのブートアプリすべて(認証サーバー、リソースサーバー、および両方のクライアントアプリケーション)が稼働している必要があります。
次に、Chromeなどのブラウザを開き、クレデンシャル[email protected]/123を使用してClient-1にログインします。 次に、別のウィンドウまたはタブで、Client-2のURLを押します。 ログインボタンをクリックすると、認証手順をバイパスして、すぐにFoosページにリダイレクトされます。
同様に、ユーザーが最初に Client-2 にログインする場合、Client-1のユーザー名/パスワードを入力する必要はありません。
6. 結論
このチュートリアルでは、SpringSecurityOAuth2を使用したシングルサインオンとKeycloakをIDプロバイダーとして使用したSpringBootの実装に焦点を当てました。
いつものように、完全なソースコードはGitHubのにあります。