2020年12月31日木曜日

アクセス制御の実装サンプル解説(5) - 対話グリッド

 こちらの記事の継続です。

対話グリッドの追加


アプリケーションに対話グリッドのページを追加します。アプリケーション・ビルダーからページの作成を実行します。


ページ・タイプコンポーネントに含まれるフォームをクリックします。


編集可能対話グリッドをクリックします。


ページ名は任意ですが、ここではグリッド編集としています。ページ・モード標準を選択し、へ進みます。


ナビゲーションのプリファレンス新規ナビゲーション・メニュー・エントリの作成を選択します。新規ナビゲーション・メニュー・エントリはページ名と同一のグリッド編集になるので、そのままにして、へ進みます。


表/ビューの名前としてPAC_TASKS(表)を選択します。

列がデフォルトですべて選択されますが、をクリックして開いて、ダイアログを拡大するか下にスクロールするかしないと、主キー列の設定が見つかりません。

主キー列の設定をデフォルトのROWIDからTASK_ID(Number)へ変更し、作成をクリックします。


ページが作成されたら、実行して作成された対話グリッドのページを確認します。サインインする従業員は誰でもかまいません。


対話グリッドのページが表示されます。


対話モード・レポートと同様にProject Id列とAssigned To列が数値のままなので、LOVに基づく表示に変更します。

ページ・デザイナにて対話グリッドのページを開きます。

最初に列PROJECT_IDを選択し、タイプ選択リストLOVタイプ共有コンポーネントLOVPAC_PROJECTS.PROJECT_NAME追加値の表示OFFNULL表示値-プロジェクトを選択 -と設定します。


次に列ASSIGNED_TOを選択し、LOVとしてPAC_EMPLOYEES.EMPLOYEE_NAMENULL表示値- 従業員を選択 -とし、その他は同じ設定を行います。


最後に列STATUSを選択し、LOVとしてLOV_TASK_STATUSNULL表示値- ステータスを選択 -とし、その他は同じ設定を行います。


これで変更が完了です。結果を確認するために、ページの保存と実行をします。

対話グリッドのProject Id列、Assigned To列、Status列が設定されたLOVを元に表示されていることが確認できます。


以上で対話グリッドの追加は完了しました。

対話グリッドのアクセス制限


対話グリッドもレポートの一種なので、クラシック・レポートや対話モード・レポートと同様のSQLによってリストを制限できる、というのは編集可能でない場合のみです。編集可能な対話グリッドのソースとなるSQLは、更新可能な形で記述しなければなりません。具体的には、from句で他の表との結合(JOIN)をしないよう記述します。(対話グリッドで結合を含む複数の表を扱う方法については、こちらの記事が参考になります)。

今回の要件を満たす更新可能な対話グリッドのソースとして、以下のSQLを設定します。
select PROJECT_ID,
       TASK_ID,
       TASK_NAME,
       ASSIGNED_TO,
       STATUS,
       START_DATE,
       END_DATE,
       COST,
       BUDGET,
       (
           select group_name from pac_employees
           where t.assigned_to = employee_id
       ) as group_name
  from PAC_TASKS t
  where 
  :G_IS_ADMINISTRATOR = 'Y'
  or
  exists 
  (
      select 1 from pac_employees
      where t.assigned_to = employee_id
      and group_name = :G_GROUP_NAME
  )
ページ・デザイナにて対話グリッドのページを開き、ソースタイプSQL問合せに変更し、上記のSQLを設定します。


列にGROUP_NAMEが新しく追加されます。この列は表PAC_TASKSに含まれていないので、更新の対象にはできません。そのため、列GROUP_NAMEを選択し、ソース問合せのみONにし、更新の対象から外します。


また、GROUP_NAMEつまり部門の値は、ASSIGNED_TOとして設定される従業員から導出される値であるので、任意に設定はできません。読取り専用タイプ常時実行1回とします。


リストされる行の制御は以上で完了です。ページを実行して確認してみます。管理者ロールを持つ従業員とそれ以外の従業員でそれぞれサインインし、リスト内容を見てみます。

管理者ロールを持つ従業員では、全行リストされていることが確認できます。


管理者ロールを持たない場合は、リストされる行が、サインインした従業員の所属する部門に制限されています。


対話グリッドの更新に適用するアクセス制御はAttributesに含まれるプロパティとして設定します。

編集に含まれる有効実行可能な操作は対話グリッド自体の設定です。今回はすべての編集操作を使うので、すべて有効にします。

最初に認可の編集追加更新削除をすべてコントリビューション権限に設定し、動作を確認してみます。今回の要件では、追加、削除についてはコントリビューション権限の有無のみで決定されますが、更新についてはそれ以外にタスクの担当者も更新可能にする必要があります。こちらの対応は、後ほど実装します。


最初にコントリビュータ・ロールを持つ従業員でサインインします。対話グリッドのページを表示します。

対話グリッドに編集保存行の追加ボタンが表示されています。


アクション・メニュー選択にも、行の削除など、各種データ操作を行う項目が含まれています。


それぞれの行の操作についても同様です。


一般の従業員でサインインして、これらのメニュー項目について確認します。

編集に関するボタンがなくなり、アクション・メニュー選択からも、項目が無くなっています。


行の操作についても項目が無くなっていて、かつ、どこのデータをクリックしても編集モードにはなりません。


作成と削除については、これで要件を満たしていますが、編集については行単位でアクセス制御を行う必要があります。

これを実装するために、プロパティの許可された行操作列の指定を使います。

対話グリッドのSQLに列ALLOWED_OPERATIONSを加えます。サインインした従業員がコントリビュータ・ロールを持っていればUD(U - 編集可、D - 削除可)、コントリビュータ・ロールがなくてもASSIGNED_TO、つまり担当者が自分自身であればU(U - 編集可)を返します。それ以外は空文字列で行の操作を許可しません。
select PROJECT_ID,
       TASK_ID,
       TASK_NAME,
       ASSIGNED_TO,
       STATUS,
       START_DATE,
       END_DATE,
       COST,
       BUDGET,
       (
           select group_name from pac_employees
           where t.assigned_to = employee_id
       ) as group_name,
       case
       when :G_IS_CONTRIBUTOR = 'Y' then
         'UD'
       when assigned_to = (
           select employee_id from pac_employees
           where employee_name = :APP_USER
       ) then
         'U'
       else
         ''
       end allowed_operations
  from PAC_TASKS t
  where 
  :G_IS_ADMINISTRATOR = 'Y'
  or
  exists 
  (
      select 1 from pac_employees
      where t.assigned_to = employee_id
      and group_name = :G_GROUP_NAME
  )

Attributes許可された行操作に列ALLOWED_OPERATIONSを指定し、認可の編集更新よりコントリビューション権限を除きます。


ALLOWED_OPERATIONSがレポートに表示されないよう、タイプ非表示に設定します。アクセス制御の設定は存在自体を、エンドユーザーから隠す必要があります。また、更新もできない列なので、問合せのみONにします。


以上で行単位でのアクセス制御の実装ができました。ページを実行して動作を確認します。

一般従業員でサインインします。Assigned Toがサインインした従業員と同じ行は更新ができ、そうでない行は更新が不可になっていることが確認できます。


ASSIGNED_TO(担当者)の入力について、フォームと同様に、全従業員を選択できてしまう状態になっています。こちらの対応を行います。


一般従業員でサインインした場合は、ASSIGNED_TO(担当者)は変更不可、つまり読取専用とします。

ASSIGNED_TOを選択し、読取り専用タイプとしてアイテム != 値を選択し、アイテムG_IS_CONTRIBUTORを選択します。としてY、つまりG_IS_CONTRIBUTOR != Y、コントリビュータ・ロールを持っていなければ読取り専用とする、という条件を設定します。実行1回で行ごとの評価は行いません。


また、コントリビュータ・ロールを持ったユーザーがASSIGNED_TO(担当者)を選択する際に、自部門の担当者のみがリストされるよう設定します。

最初に共有コンポーネントより、以前に登録したLOVであるLOV_EMPLOYEES_IN_GROUPを開きます。その設定のWHERE句
group_name = :G_GROUP_NAME

から

group_name = :G_GROUP_NAME
or
:G_IS_ADMINISTRATOR = 'Y'

へ変更し、変更の適用をクリックします。


変更したLOVを使用するよう、列ASSIGNED_TOLOVLOV_EMPLOYEES_IN_GROUPに設定し、念のため追加値の表示ONにします。LOVの戻り値に含まれないASSIGNED_TOの値は出現しないはずですが、考え違いで含まれていた場合に、そのデータをそのまま表示します。


ページを実行して、変更した設定の効果を確認してみます。

最初に一般従業員でサインインします。列Assigned Toについては、担当者であっても編集可能にならないことが確認できます。


次に、コントリビュータ・ロールを持つ従業員でサインインします。列Assigned Toをクリックすると選択可能な従業員のリストがポップアップしますが、自部門に所属している従業員に限られています。


最後に、管理者ロールを持つ従業員でサインインします。列Group Name(部門)が異なっていても列Assigned Toに従業員名が表示されています。LOV_EMPLOYEES_IN_GROUPのWHERE句に加えた:G_IS_ADMINISTRATOR = 'Y'の条件が機能していることが確認できます。


対話グリッドのアクセス制御の実装についての説明は以上です。

さて、管理者ロールでサインインした際に表示されている対話グリッドを見返してみましょう。

編集保存行の追加のボタンが表示されているので、コントリビューション権限を持っていることがわかります。


今回の要件では、管理者による編集作業を想定していません。そのため、コントリビュータ・ロールを持つ従業員のみがコントリビューション権限を持つように設定を変更する必要があります。

次は本シリーズの最後の記事になりますが、認可スキームそのものについて説明します。

ちなみに、フォーム・リージョンも同様にAttributes許可された表操作列認可の編集といったプロパティがあります。対話グリッドに追加した列ALLOWED_OPERATIONSをフォームにたいして定義するには、以下のようにフォームのソースであるSQL問合せを変更します。


フォームの場合は対話グリッドと異なり、Attributesの設定と連動して作成変更の適用削除、といったボタン表示/非表示ページ・アイテム編集不可/編集可能といった状態は変わらず、ボタンやページ・アイテムそれぞれに条件を設定する必要があります。そのため、対話グリッドよりは、Attributesに含まれるプロパティを設定してアクセス制御を行う利点は少ないです。とはいえ、リージョンにアクセス制御を設定しておくと、特にボタンの設定に間違いがあった場合でも該当の処理が行われないため、より安全になります。