Oracle REST Data ServicesのREST APIをOAuth2によって保護する手順と、保護されたREST APIをAPEXから呼び出す方法について確認します。
確認作業にはAlways FreeのAutonomous Databaseを使用します。
最終的に、OAuth2の認証で保護されたREST APIを呼び出すAPEXアプリケーションを作成します。
APEXでワークスペースを作成し、同時にワークスペース・スキーマも作成している(スキーマ名はWKSP_ワークスペース名)という環境を前提とします。
最初に呼び出すREST APIを準備します。サンプルのHRサービスをインストールします。
SQLワークショップのRESTfulサービスを開きます。
ORDSにスキーマを登録をクリックし、スキーマを登録します。
ダイアログが開きます。
RESTfulサービスの有効化はON、スキーマ別名として(WKSP_で始まるスキーマ名ではなく)ワークスペース名がデフォルトで設定されます。サンプル・サービスのインストールをONにします。ここでインストールされるサンプル・サービスを使って、確認作業を行います。メタデータ・アクセスに必要な認可はOFFから変更しません。
スキーマ属性の保存をクリックします。
スキーマが有効化され、サンプル・サービスがインストールされます。
REST APIの動作を確認します。
モジュールoracle.example.hr、テンプレートemployees/のGETハンドラを開きます。
完全なURLをコピーし、ブラウザで呼び出します。JSON形式のレスポンスが表示されたら、サンプルのインストールは完了です。
ひとつ気になった点があります。
APEXより作成されたスキーマが持つ権限が、データベース・アクション(ORDS)から見ると足りないと報告されます。
データベース・アクションのデータベース・ユーザーより該当するワークスペース・スキーマの編集を開きます。
CONNECTとRESOURCEのロールが無い、と言われます。
Oracle Databaseのドキュメント2日でデータベース管理者に、以下の記載があります。
ノート:
これらのロールに依存せずに、データベース・セキュリティ用に独自のロールを設計することをお薦めします。
これらのロールは、将来のリリースのOracle Databaseでは自動生成されない可能性があります。
なので、とりあえずこの警告は無視します。以前に作成したワークスペースでは、ワークスペース・スキーマの権限よりCREATE SESSIONが抜けている場合があるようです。そのような場合は、CREATE SESSIONの権限をワークスペース・スキーマに割り当てます。
GRANT CREATE SESSION TO ワークスペース・スキーマ;
これからロールや権限を定義します。APEXの画面とデータベース・アクションの両方から、同じ作業を実施できます。RESTサービス自体はOracle REST Data Servicesのチームが開発しているのですが、正直にいってAPEXの開発者にとってはAPEXのインターフェースの方が使いやすいです。
APEXからは、OAuth2のクライアントの作成とロールの割り当てを行うGUIは提供されていません。そのため、SQLコマンドよりパッケージOAUTHのプロシージャを呼び出す必要があります。OAuth2のクライアントの管理はデータベース・アクションの方が容易ですが、APEXのインターフェースを使って以降の作業を進めます。
まず、ロールを作成します。
左ペインのツリーからロールを選択し、右ペインのロールの作成をクリックします。
ロール名はHR Example Roleとします。
ロールの作成をクリックします。
ロールHR Example Roleが作成されます。
次に権限を作成します。
左ペインのツリーから権限を選んで、右ペインの権限の作成をクリックします。
名前はoracle.example.hr、タイトルはHR Exampleとします。
ロールにHR Example Roleを選択し、保護されたモジュールとしてoracle.example.hrを選択します。
保護されたリソースとして、モジュール全体ではなく、個別のテンプレートごとに保護を設定することもできます。
権限の作成をクリックします。
この時点でRESTモジュールのoracle.example.hrは、呼び出しの際にOAuth2による認証が必要になっています。
OAuth2のクライアントとしてHR Clientを作成します。作成したクライアントにロールHR Example Roleを割り当てます。OAUTH.CREATE_CLIENTの引数p_grant_typeはつねにclient_credentialsです。(APEXはclient_credentialsのみをサポートしているため)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
begin | |
-- クライアントHR Clientを作成する。 | |
oauth.create_client( | |
p_name => 'HR Client' | |
,p_grant_type => 'client_credentials' | |
,p_description => 'Sample HR Client' | |
,p_support_email => 'yuXX@acme.com' | |
,p_privilege_names => NULL | |
); | |
-- HR ClientにロールHR Example Roleを割り当てる。 | |
oauth.grant_client_role( | |
p_client_name => 'HR Client' | |
,p_role_name => 'HR Example Role' | |
); | |
end; |
クライアントが作成されたら、CLIENT_IDとCLIENT_SECRETを確認します。USER_ORDS_CLIENTSビューを検索します。
select name, client_id, client_secret from user_ords_clients;
これらの値は、APEX側からREST APIを呼び出す際に使用します。コピーして保存しておきます。
select * from user_ords_client_roles;
以上でREST API側の準備は完了です。
これより作成したREST APIを呼び出すAPEXアプリケーションを作成します。
最初にWeb資格証明を作成します。
アプリケーション・ビルダーのワークスペース・ユーティリティを開きます。
Web資格証明を開きます。
名前はHR Example Cred、静的識別子はHR_EXAMPLE_CREDとします。
認証タイプとしてOAuth2クライアント資格証明フローを選択し、クライアントIDまたはユーザー名に、USER_OAUTH_CLIENTSビューの列CLIENT_IDとして取得した値、クライアント・シークレットまたはパスワードに、列CLIENT_SECRETとして取得した値を設定します。
以上で作成をクリックします。
Web資格証明HR Example Credが作成されます。
アプリケーション作成ウィザードを起動し、空のアプリケーションを作成します。名前はORDS REST Testとします。
アプリケーションが作成されたら、共有コンポーネントのRESTデータ・ソースを開きます。
リモート表EMPを一覧するRESTデータ・ソースを作成します。
作成をクリックします。
RESTデータ・ソースの作成は最初からを選びます。
次へ進みます。
URLエンドポイントとして、モジュールoracle.example.hr、テンプレートemployees/の完全なURL(REST APIのテストに使用したURL)を入力します。
次へ進みます。
リモート・サーバー、ベースURL、サービスURLパスは自動で検出されます。変更は不要です。
次へ進みます。
OAuthトークンURLは自動的に設定されます。APEX_WEB_SERVICE.MAKE_REST_REQUESTを使ってPL/SQLからREST APIを呼び出す際に、このOAuthトークンURLを引数p_token_urlに指定します。そのため、この値は後で使用します。
検出をクリックします。
RESTデータ・ソースの作成をクリックします。
RESTデータ・ソースRemote EMP Tableが作成されました。
このRESTデータ・ソースをソースとした対話モード・レポートを作成します。
ページの作成を実行します。
対話モード・レポートを選択します。
ページの作成を実行します。
対話モード・レポートのページが作成されます。
ホーム・ページにサンプルを実装します。
従業員番号を指定するページ・アイテムを作成します。
識別の名前はP1_EMPNO、タイプはテキスト・フィールド、ラベルはEmpnoとします。
識別のタイトルはEMP、タイプとして動的コンテンツを選択します。
ソースのCLOBを返すPL/SQLファンクション本体として以下を記述します。
APEX_WEB_SERVICE.MAKE_REST_REQUESTに引数p_token_urlが指定されている場合、内部の処理としてAPEX_CREDENTIAL.SET_SESSION_TOKENが呼び出されているようです。トークンURLを呼び出して得られたOAuth2のアクセス・トークンはキャッシュされ、トークンがエクスパイアすると再度トークンURLが呼び出されます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
declare | |
l_response blob; | |
l_pretty clob; | |
l_apex_path varchar2(400); | |
l_pattern varchar2(80); | |
begin | |
/* URLの先頭部分 */ | |
l_apex_path := apex_util.host_url('APEX_PATH'); | |
/* ORDSスキーマ・エイリアス */ | |
select pattern into l_pattern from user_ords_schemas | |
where parsing_schema = sys_context('USERENV','CURRENT_USER'); | |
/* REST APIの呼び出し - p_token_urlを指定する。 */ | |
apex_web_service.clear_request_headers; | |
l_response := apex_web_service.make_rest_request_b( | |
p_url => l_apex_path || l_pattern || '/hr/employees/' || :P1_EMPNO | |
,p_http_method => 'GET' | |
,p_credential_static_id => 'HR_EXAMPLE_CRED' | |
,p_token_url => l_apex_path || l_pattern || '/oauth/token' | |
); | |
if apex_web_service.g_status_code <> 200 then | |
raise_application_error(-200001, 'REST API Error'); | |
end if; | |
/* JSONの整形 */ | |
select json_serialize(l_response returning clob pretty) into l_pretty from dual; | |
return l_pretty; | |
end; |
送信するページ・アイテムとしてP1_EMPNOを指定します。
プリティ・プリントを適用したJSON出力の改行を表示させるため、ヘッダーおよびフッターのヘッダー・テキストとして<pre>、フッター・テキストとして</pre>を記述します。
動的コンテンツをリフレッシュするボタンを作成します。
識別のボタン名はFIND、ラベルはFind、動作のアクションとして動的アクションで定義を選択します。
ボタンFINDに動的アクションを作成します。
識別の名前はRefresh EMPとします。タイミングはデフォルトでイベントがクリック、選択タイプがボタン、ボタンがFINDになります。
TRUEアクションとしてリフレッシュを選択します。影響を受ける要素の選択タイプはリージョンとし、リージョンにはJSONを出力する動的コンテンツであるEMPを指定します。
以上でOAuth2の認証で保護されたREST APIを呼び出す、確認アプリケーションは完成です。
今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/ords-rest-test.zip
Oracle APEXのアプリケーション作成の参考になれば幸いです。
完