プリザンターのレコードのアクセス制御を使いこなす

本記事は [Pleasanter(プリザンター) Advent Calendar 2021](https://qiita.com/advent-calendar/2021/pleasanter) 1日目の記事です。

# 概要
プリザンターは、1つのテーブルでレコード単位のアクセス制御が行えます。組織やグループに見せる範囲を限定することで、実用的なアプリケーションを開発することができます。本記事ではレコードのアクセス制御を実現する複数の方法について説明します。

## レコードのアクセス制御の種類
レコードのアクセス制御を実現する方法は下記の通りです。

1. [レコードに直接権限を付与する方法](#レコードに直接権限を付与する方法)
1. [レコード作成時に自動的に権限を付与する方法](#レコード作成時に自動的に権限を付与する方法)
1. [拡張SQLでレコードが抽出されるようにする方法](#拡張sqlでレコードが抽出されるようにする方法)
1. [サーバスクリプトのview.Filtersでレコードが抽出されるようにする方法](#サーバスクリプトのviewfiltersでレコードが抽出されるようにする方法)
1. [拡張SQLとサーバスクリプトの組み合わせでレコードが抽出されるようにする方法](#拡張sqlとサーバスクリプトの組み合わせでレコードが抽出されるようにする方法)

## レコードに直接権限を付与する方法
この方法は最もシンプルな方法ですが、レコード1つ1つに設定を行う必要があるため、レコード数が多い場合など運用が難しいケースが多いです。操作方法は、レコードの編集画面の「レコードのアクセス制御」タブを開き、任意のアクセス権を付与します。この操作を行うにはテーブルまたはレコードに対して「権限の管理」権限が必要です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/bb693cb4-1f38-4065-d58a-9aaa03d7de8b.png)

## レコード作成時に自動的に権限を付与する方法
この方法は、レコードを作成した人に自動的に権限を付与する方法です。レコードを作成したタイミングで権限が付与されるため[レコードに直接権限を付与する方法](#レコードに直接権限を付与する方法)に比べ、運用しやすいのが特徴です。利用者からの問い合わせを受け付けて、回答するような業務に適しています。利用者には「サイトのアクセス制御」で「作成」権限のみを付与し、レコードが作成されたタイミングでレコードに「読み取り」権限が追加されるように設定します。この方法はレコードの作成時にのみ自動的にアクセス権を付与する仕組みです。レコードの更新時には動作いたしません。

#### 設定方法
「テーブルの管理」「サイトのアクセス制御」タブで「利用者グループ」に「作成」権限を付与します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/144afcc4-6a40-879c-1e20-1955bea01bfd.png)

「テーブルの管理」「レコードのアクセス制御」タブで「ユーザ」に「読み取り」権限を付与します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/8b385577-b2b4-f5c4-7db5-aa1a3d47dfc7.png)

「利用者グループ」のユーザでログインすると新規作成のみ行うことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/33539775-63bd-1a80-d140-e5a788cfc52b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/143af4ce-9324-36ee-07b6-57f646170735.png)

自分で作成したレコードは閲覧することができます。レコード作成時に自動的に読み取り権限が付与されているためです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/a215381c-c2e3-000e-023b-64423f9c219e.png)

## 拡張SQLでレコードが抽出されるようにする方法
ここからは高度な方法です。レコードに権限を付与する方法と異なり、レコード取得時のSQLにWhere句を追加することで柔軟なアクセス制御を実現します。拡張SQLはブラウザで設定することができません。サーバのディレクトリに設定ファイルとSQLを書いたファイルを格納することで実装します。拡張SQLで実装したSQLは一覧画面だけでなく編集画面でも有効です。編集画面のURLを直接要求された場合でも、Where句の条件に該当しないレコードを表示することはできません。

#### 設定方法
設定ファイル（Test.json）とSQLを書いたファイル（Test.json.sql）を準備します。Testの部分は任意のファイル名に変更可能です。ファイルはプリザンターの起動時に読み込まれるため、ファイルを格納した後にプリザンターを再起動する必要があります。SQL文は全体をカッコで囲む必要があります。SQL文にはサブクエリも使用可能です。下記の例ではサイトID 2 のテーブルで、管理者（Manager）または担当者（Owner）が自分自身（@_U）のレコードのみを抽出します。

格納先ディレクトリ（環境に合わせて読み替えてください）

```
C:\web\pleasanter\Implem.Pleasanter\App_Data\Parameters\ExtendedSqls
```

Test.json： サイトID 2 でWhere句を追加します。

```JSON
{
    "SiteIdList": [ 2 ],
    "OnSelectingWhere": true
}
```

Test.json.sql： 管理者（Manager）または担当者（Owner）が自分自身のレコードのみを抽出します。@_UにはユーザIDが格納されます。下記は期限付きテーブルの例です。記録テーブルの場合には"Issues"の部分を"Results"に変更してください。

```SQL
("Issues"."Manager" = @_U or "Issues"."Owner" = @_U)
```

## サーバスクリプトのview.Filtersでレコードが抽出されるようにする方法
拡張SQLを使用する方法は柔軟なSQLを実装することができますが、設定時にサーバの再起動が必要です。サーバスクリプトのview.Filtersを使用するとサーバの再起動を行わずに柔軟なアクセス制御を実現します。また、サーバスクリプトを使用するとJavaScriptを使用してフィルタの適用条件を制御することが可能です。[拡張SQLでレコードが抽出されるようにする方法](#拡張sqlでレコードが抽出されるようにする方法)と同様に一覧画面だけでなく編集画面でも有効です。

#### 設定方法
「テーブルの管理」「サーバスクリプト」タブで「新規作成」をクリックします。表示されたダイアログに下記のようにスクリプトを記述します。「条件」は「ビュー処理時」にのみチェックします。下記の例ではグループID 1 に所属していないユーザに対し、管理者（Manager）または担当者（Owner）が自分自身（context.UserId）のレコードのみを抽出します。view.Filtersにor_で始まる任意のフィルタ名にセットすることでor条件での抽出が可能です。

```JavaScript
let group = groups.Get(1);
if (!group.ContainsUser(context.UserId)) {
    let data = {};
    data.Manager = `["${context.UserId}"]`;
    data.Owner = `["${context.UserId}"]`;
    view.Filters.or_MyFilter = JSON.stringify(data);
}
```

## 拡張SQLとサーバスクリプトの組み合わせでレコードが抽出されるようにする方法
サーバスクリプトのview.Filtersでは実装できないような複雑なWhere句を拡張SQLで実装し、サーバスクリプトから条件によって拡張SQLの適用をコントロールすることができます。この方法は最も柔軟なアクセス制御を行うことが可能です。

#### 設定方法
名前付きの拡張SQLをセットして、サーバスクリプトのビュー処理時に呼び出します。下記の例ではグループID 1 に所属していないユーザに対し、管理者（Manager）または担当者（Owner）が自分自身（@_U）のレコードのみを抽出します。

格納先ディレクトリ（環境に合わせて読み替えてください）

```
C:\web\pleasanter\Implem.Pleasanter\App_Data\Parameters\ExtendedSqls
```

Test.json： "Name":"SelectingWhereName"、"SpecifyByName":true、"OnSelectingWhere":trueとします。

```JSON
{
    "Name": "SelectingWhereName",
    "SpecifyByName": true,
    "OnSelectingWhere": true
}
```

Test.json.sql： 管理者（Manager）または担当者（Owner）が自分自身のレコードのみを抽出します。@_UにはユーザIDが格納されます。下記は期限付きテーブルの例です。記録テーブルの場合には"Issues"の部分を"Results"に変更してください。

```SQL
("Issues"."Manager" = @_U or "Issues"."Owner" = @_U)
```

サーバスクリプト：ビュー処理時

```JavaScript
let group = groups.Get(1);
if (!group.ContainsUser(context.UserId)) {
    view.Filters.OnSelectingWhere = 'SelectingWhereName';
}
```

## 注意事項
プリザンターの横断検索は拡張SQLやサーバスクリプトのview.Filtersによるアクセス制御が行えません。拡張SQLやサーバスクリプトのview.Filtersを使用した場合には、対象のテーブルが横断検索にヒットしないよう下記の設定を行ってください。

テーブルの管理：検索：検索の設定：横断検索を無効化
https://pleasanter.org/manual/table-management-disable-cross-search

## おわりに
プリザンターは今後も業務に役立つローコード開発プラットフォームとして進化を続けてまいります。応援よろしくお願いします。皆さん良いクリスマスをお過ごしください。
https://pleasanter.org
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78230/1764addf-fe7a-b707-0d06-d84ad7899014.png)