ServiceNow – Before Query Business Ruleの解説

開発・導入

ServiceNowにおいて、テーブルに対して論理削除フラグや有効期限の実装、権限制御を行うときに利用できるBusiness Ruleの一種である、Before Queryについて解説します。

Before Queryとは?

Before Queryの機能概要

Before QueryはBusiness Ruleの一種で、特定のテーブルに対するクエリ(参照)が発生した際に、元のクエリに割り込む形でクエリ条件(レコードの抽出条件)を強制的に追加する機能です。

具体例として、User[sys_user]テーブルに標準で設定されているBefore Queryである”user query”を見てみましょう。このBefore Queryは、admin/user_adminロールを持たないユーザがユーザのリストやフォームなどを開いた場合に、非アクティブなユーザが表示されないように制御しています。

補足として、もう少しだけ細かく解説します。

Condition項目は、Before Queryが動作する条件を設定しています。isInteractive()関数は、現在のセッションが他システムからのAPIコールなどではなくユーザがWebUIから開始されているかを確認しています。hasRole()関数はユーザがロールを保持しているかを確認しています。

Script項目は、どのようなクエリ条件を追加するかを指定しています。current変数は現在参照しようとしているテーブル・レコードにアクセスするためのGlideRecordオブジェクトであり、addActiveQuery()メソッドはテーブルへのクエリ(参照)時に「Active項目がtrueのレコードのみ」という条件を付加する関数です。

GlideRecordオブジェクトやaddActiveQuery()については次の記事でより詳しく解説しています。

ServiceNow – GlideRecordのイメージと使い方 図解解説 | ServiceNow研究所 (servicenow-lab.com)

Before Queryの適用範囲

Before Queryは、ユーザがリストやフォーム、レポートなどを開いたときに発生するテーブルへのクエリ(参照)はもちろん、スクリプト中のGlideRecord APIなどからクエリ(参照)した場合、さらにはImpersonate機能において対象ユーザを選択する際やSSOログインの際に既存ユーザと認証キー(NameID)を突合する際など、ユーザがカスタマイズすることができないコア機能からのクエリ(参照)など、あらゆる経路からのクエリ(参照)に対して適用されます。

Before Queryの活用方法

Before Queryには主に2種類の活用方法があります。

論理削除フラグ、有効期限の実装に使う

具体例として紹介したUser[sys_user]テーブルにおける”user query”と同様の活用方法です。

一般的なシステムにおいて、テーブルに論理削除を実装するためには、DB側(テーブル側)にActive項目やDeleted項目といった論理削除フラグを用意した上で、アプリ側では論理削除フラグを考慮してクエリを発行する必要があります

しかしServiceNowでは、Before Queryを利用することで、論理削除フラグの実装をテーブル側の設定で完結させることができ、アプリ側は論理削除を意識する必要がなくなります

Department[cmn_department]テーブルに論理削除を実装する

具体例として、標準のDepartment[cmn_department]テーブルに論理削除を実装してみます。

まずは、テーブルにActive項目を追加します。

次に、Department[cmn_department]テーブルにBusiness Ruleを追加します。設定はUser[sys_user]テーブルの”user query”とほぼ同じですが、Active項目がカスタム項目なので、addActiveQuery()は使えず、addQuery()でクエリ条件を追加する必要があります。

この設定を行うと、下図のようにadminユーザでは全てのDepartmentレコードが、itilユーザではActiveなDepartmentレコードのみが表示されるようになりました。

同様に、例えば組織の有効日を管理したければ、開始日付、終了日付項目を作成し、現在日付が開始日付~終了日付の間にある場合のみ表示するようにします。

(補足) 論理削除が必要になるケース

ServiceNowにおいて、論理削除が必要になる場合について補足しておきます。例えばUser[sys_user]テーブルは、Incident[incident]テーブルにおけるAssigned to(アサイン者)項目からReferenceされており、もしユーザを物理削除してしまうと、その人が過去に担当していたインシデントレコードにおいて、その人が担当したことが後から追えなくなってしまいます

同様に、他のテーブルからReferenceされているテーブルは、参照先のレコードを物理削除すると、参照元のレコードからたどることができなくなってしまうため、業務要件として論理削除にしたい場合はもちろん、ログの保存や監査の要件から論理削除の実装が求められることがあります

なお、Before Queryによって論理削除されたレコードを参照している参照元レコード上では、論理削除されたレコードは次のように見えます。Display value=表示値は参照元レコードにも保持されているため、論理削除されていることによる影響はぱっと見はわかりませんが、Informationアイコン(iマーク)を押すと、レコードが存在していないように見えます。

権限制御(非推奨)

もう一つの活用方法が、権限制御です。Before Queryはテーブルのクエリ(参照)に対してローレイヤーで強制的に割り込んでクエリ条件を追加できる強力な機能ですので、個人情報やお金などのセンシティブな情報が保持されているテーブルの権限制御のために使われることがあります

この活用方法は後述の理由で個人的には非推奨ですが、実務上採用されている事例をしばしば見かけるため一応紹介しておきます。

admin/user_adminを持たないユーザは自分と同じ会社のユーザの情報しか閲覧できないようにする

標準では、User[sys_user]テーブルには閲覧制御がかかっておらず、ユーザは互いの情報を閲覧することができます。(とはいえ、ユーザテーブルにアクセスするためのメニューには権限制御がかかっているため、ServiceNowの仕様を知っている人が直接テーブルにアクセスしない限り、通常は互いの情報を見ることはありません)

そこで、自分と同じ会社のユーザの情報しか閲覧できないように制御したいとします。この場合のBefore Queryのコードを示します。

Before Queryを権限制御に使うべきではない理由

Before Queryを用いることで権限制御を実現することはできますが、個人的には主に2つの理由で推奨しません。

理由1. より適切な機能が存在する

前述の例のような、会社によってユーザの閲覧範囲を絞るような場合は、インスタンスを論理的に分割するDomain Separationや、互いに情報を閲覧できてはいけない複数の企業のユーザが使う前提で作られているCustomer Service Management (CSM)を活用するのがより適切です。

また、より小さい範囲、例えばDepartment(部署)に基づいた権限制御を行う場合も、標準の権限制御機能であるACLを使うべきです。

ServiceNowのAccess Control List(ACL)の概要と評価のプロセス | ServiceNow研究所 (servicenow-lab.com)

それでもACLではなくBefore Queryが使われる場合としては、ACLによってあるレコードが閲覧できない場合、権限の制約でレコードが閲覧できない旨のメッセージが表示されるのに対し、Before Queryではユーザからは権限の制約でレコードが閲覧できないことは一切わからず、あたかも初めからレコードが存在しないように見え、こちらのほうが好ましいという場合です。

この仕様の捉え方は人によって異なりますが、私の経験上、どちらを支持する人もいました。Before Queryを支持する意見の中で、こちらの記事に記載されている「ACLの場合、1000件中閲覧可能な5件を見るためには(1ページ当たり100レコード表示している場合、最悪10ページ分)ページ送りをしなければならないためUXが低下する」というのはある程度説得力があるなと感じました。

しかしこれについては、リストへ誘導する導線(Moduleなど)において、閲覧可能なレコードのみに絞り込んでおけばよいので、この仕様はBefore Queryによる権限制御を正当化するものにはならないと考えます。

理由2. パフォーマンスに悪影響を及ぼす可能性が高い

シンプルな権限制御であれば、基本的にはノーコード・ローコードでACLで実装が可能ですが、ACLは権限制御の条件が複雑になると設計・実装の難易度が高まるため、いっそBefore QueryのScriptで書いてしまったほうが楽な場合があります。

しかし、複雑な権限制御を実現するために安易にBefore Queryを採用してしまうと、パフォーマンスに悪影響を及ぼす可能性が高いです。実際にパフォーマンスが悪化し、クエリの改善を行った事例がありました。

この場合は、権限制御の要件を妥協してもう少しシンプルにすることができないかを考えるべきでしょう。

Before Queryの注意点

Before Queryはあらゆる経路からのクエリ(参照)ローレイヤーで強制的に割り込んでクエリ条件を追加する強力な機能ですので、取り扱いには注意が必要です。

注意点1. パフォーマンスへの影響

まず注意すべきなのは、パフォーマンスへの影響です。特に、データ数が多くなりがちなトランザクション系のテーブルに対してBefore Queryを設定すると、データ量の増加に伴いクエリ(参照)のパフォーマンスが悪くなることがあります。特に、多くのクエリが発行されるダッシュボードの表示時などに影響が出やすいです。

当然、データ数が少ないマスタ系のテーブルであっても、複雑なスクリプトが組まれている場合は危険です。

そのため、Before Queryを活用するのはデータ数の少ないマスタ系のテーブルのみ、かつシンプルな制御のみとすべきです。

注意点2. 想定外の動作が起こることがある

Before QueryはServiceNowのコア機能が当該テーブルにアクセスする際にも作用します。そのため、次のような想定外の動作に繋がった事例がありました。

  • User[sys_user]テーブルに設定したBefore Queryが原因で、Impersonate時にユーザが選べない
  • User[sys_user]テーブルに設定したBefore Queryが原因で、SSOができない

このような想定外の動作の発生を避けるためには、Condition項目においてisInteractive()関数やhasRole()関数を活用することで、適切な条件の場合のみ動作するようにすることです。特に、具体例として紹介した”user query”で考慮されているような、外部システムからのAPI経由でのテーブルアクセスや、管理者権限を持つユーザからのアクセスした場合に制御をかけるべきかは設計時に考える必要があります

以上です。

コメント

タイトルとURLをコピーしました