目次
はじめに
言うまでもないのですが、、、
例えば
個人情報取得だったり、指定の口座に入金するなどのAPIの場合、
誰でも呼び出せる状態にしておくのは大問題です。
スマホのアプリやWebサイトにログイン機能があるように、
APIにも認証済みクライアント(ユーザをイメージしてもらって大丈夫です)から呼び出された時だけ処理をするような制御が必要になります。
今回はspring bootで作成したREST APIを、
誰でも呼び出せる状態にしない方法について、
keycloakとspring securityを使って解説します。
2022/3/26追記
KeycloakでSpring Bootで作成したRestAPIを保護、
SPAにKeycloakのSSO機能でログイン機能を追加、
OIDCやOAuth2.0の違い解説などなどをまとめたまとめ記事を作りました。
興味のある方は是非みてください!!

keycloakとは??
色々記事が既に出てるのでこの辺りを参考にして頂くのが早いと思います。
が、、、
一応簡単にkeycloakどんな感じで僕が業務で使ってるかを紹介すると、
ログイン機能、ユーザ管理の部分は完全にkeycloakに任せていています。
ログイン失敗連続したら30分ロックをかけるとか、
8桁以上の英数字混合のパスワードでないとパスワードポリシーとしてダメ
などのよくあるセキュリティ要件もkeycloakでポチポチやるだけで実現できるのでかなり工数削減できたりします。
こんな感じ
あとは、
自前で立ててる認証認可基盤やFacebookやTwitterに認証を移譲させるようなSSO(Single Sign On)が出来たりとか、
OAuth2.0やOpenID Connectといった仕様を満たす認証認可基盤としても利用できます。
OAuth2.0という仕様の全体概要に興味がある方はこちら参照ください。

あと、オープンソースソフトウェアなので無料で使えます。
keycloakとspring securityでアクセストークンの検証って何をすること??
図で書くとこんなイメージです。
①でクライアントはまずkeycloakとやりとりして、keycloakからアクセストークンというものを発行してもらいます。
(なんだそれってなるかもしれませんが、、、ここではこのアクセストークン発行までの流れについては長くなるのと本題ではないのでここでは触れません。)
アクセストークン発行までの流れが気になる方はこちら参照ください。

アクセストークンは、このクライアントはAPIを利用してもOKという証明になります。
②でAPIを呼び出すクライアントはこの証明を付けて呼び出します(リソースエンドポイントをコールします)。
これを受け取ったREST APIはspring securityでこの証明って正しい??有効??というのをkeycloakに対して確認(トークン検証)します。
この確認のことをトークンイントロスペクションと言います。
keycloakがこの確認で問題なしと答えた場合に初めて④のリソースの返却をします。(問題ありの場合はAPIのレスポンスは401 認証情報不足エラー)
これによって、正しいアクセストークンが発行されたクライアントだけAPIが利用できることになります。
つまり、APIが保護できることになります。
keycloakにREST APIを保護する設定のポイント解説
githubにソースコードを公開しておいたので、ローカル環境で動作確認したい場合はそちら参照ください。
(READMEに記載の通り、dockerをインストールして、docker上でkeycloakを8180ポートで立ち上げるような形になります)
keycloakの設定としては大きく3つ行います。
1.トークンイントロスペクション用のclient作成
ここで作成するclientをspring securityが使います。今回はtokenintrospectionという名前のclientを作成しました。
クライアントの種類としてはcredentialとし、secret情報を使ってkeycloakとspring securityがやりとりできるようにしておきます。
そのため、secret情報はこのあとspring側の設定ファイルに記載します。
2.アクセストークンを発行する際に利用するclientの作成
先ほどの図の①でアクセストークンを発行してもらう際には今回は別のクライアントを利用します。名前はfrontendとしました。
今度はクライアントの種類としてpublicとしてsecret情報を利用せずにkeycloakとやりとりするようにしておきます。
(SPAでフロントエンドからkeycloakとやりとりをする際はこのような設定のclientを使うのでそんな想定のやつです)
3.APIの利用を許可するユーザの作成
次に、APIを利用できるようにするユーザを作成します。
テキトーでいいです。今回はID/PASSどちらもsample001というユーザを作成しました。
ちなみに、
公開しているgithubの通りにkeycloakを立ち上げるとこの辺り設定済みの状態からスタートできるようにしてます。
spring securityでREST APIを保護する設定のポイント解説
次はspring security側の設定です。こちらも設定のポイントは3点です。
spring securityのresource serverライブラリを入れる
(mavenなんですが、、、)コードで言うとこの辺りです。
tokenintrospectionへのアクセス情報をプロパティに追加する
コードで言うとこの辺りです。
tokenintrospectionできるようにSecurityConfigクラスを作成する
コードで言うとこの辺りです。
ここではhealthと言うエンドポイントはアクセストークンなしでも呼び出せる設定にして、
そのほかのエンドポイントはアクセストークンが正しくなければ呼び出せないようにしています。
今回はhealthとhelloの2本のAPIを作成していて、helloはアクセストークン付きリクエストされないと401エラーを返すようにしています。
APIを作成して本番運用する際、
全エンドポイントにおいて、アクセストークン必須にしてしまったせいで、
死活監視(APIサーバがちゃんと動いてるかチェックするイメージ)が。。。。ってならないようにAPIを保護から除外する設定も覚えておきましょう。
APIは今回healthとhelloの2本を作成しています。
spring securityとkeycloakでREST APIが保護されるところを確認する方法解説
ここからは動作確認を3パターンしていきます。
healthはアクセストークンなしで動くことの確認
これはブラウザでAPIのエンドポイントをコールすれば確認できます。
helloはアクセストークンなしでは401エラーとなることの確認
これもブラウザでAPIのエンドポイントをコールすれば確認できます。
helloはアクセストークンが正しいと正常に動作することの確認
ここからはブラウザだとダメで。。。curlコマンドかクライアントツールを使う必要があります。
ここではchromeの拡張機能のTalend API Testerを使います。
使いたい方はこの辺り参考にしてみてください
>>Chrome拡張のTalend API TesterでAPIテスト
まず、keycloakからfrontendクライアントを利用してsample001ユーザに対してアクセストークンを発行してもらいます。(上の図でいう①のところ)
返却されたレスポンスのaccess_tokenをコピーします。
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ・・・",
"expires_in": 180,
"refresh_expires_in": 180,
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ・・・",
"token_type": "Bearer",
"id_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJYNGZ・・・",
"not-before-policy": 0,
"session_state": "a8c7af29-d11f-4a71-9ec1-87ef94380ed3",
"scope": "openid profile"
}
コピーしたaccess_tokenをAuthorizationヘッダの「Bearer 」の後ろに貼り付けてhello APIをコールすると正しくレスポンスが返却されます。
helloはアクセストークンが偽造されていると401エラーとなることの確認
先ほど、「Bearer 」の後ろに貼り付けたアクセストークンをちょっと変更してAPIを呼び出します。
そうするとinvalid_tokenエラー(error_description=”Provided token isn’t active)となることが確認できます。
アクセストークンを偽造したらちゃんと弾けるということです。
まとめ
keycloakとspring secutiryを利用してspring bootで作成したREST APIを保護する方法について解説しました。
改めて、ポイントは以下です。
keycloakの設定ポイントとしては
APIを利用したいユーザ作成、アクセストークン発行用、トークンイントロスペクション用のclient作成
spring securityの設定ポイントとしては
トークンイントロスペクション用のclient情報の設定、ライブラリ利用設定、SecurityConfigクラス作成
もしAPIの製造を担当することがあれば、
どんな感じで保護しているか??少し気にしてみてみてください。多分こんなことやってると思います。