qwc-services による Web GIS の構築 #2 認証と権限

前回は、`QGIS Server` と `QGIS Web Client 2 (QWC2)` を中核とする統合的 Web GIS エコ・システムである `qwc-services` を `qwc-docker` によってインストールし、`NapCache` とも連携させて、QGIS のプロジェクトを Web 地図として表示するところまでやりました。

- [qwc-services による Web GIS の構築 #1 qwc-docker](https://qiita.com/softark/items/bb179315d404fdd3cf9f)

現段階では、単体としての `QWC2` で実現できている事に比べて、それほど多くのことが出来るている訳ではありません。

今回は、`qwc-services` によって実現される「ユーザの認証と権限管理」の機能を見ていきます。

## 1. ユーザの認証と権限管理

通常、`"Auth"` という一つの機能として扱われることが多いのですが、「ユーザ認証」と「権限管理」の二つに分けて考える方が良いでしょう。

- ユーザ認証（`Authentication`）... ユーザが誰であるかを特定する
- 権限管理（`Authorization`）... ユーザに何が許されているかを指定する

### 1-1. ユーザの認証

`qwc-services` におけるユーザの認証は、基本的には古典的な `"ID (ユーザ名) + パスワード"` によるものです。

オプションで `TOTP`（`Time-based One Time Password`）を有効にすることも出来ますが、それについてはドキュメントの整備が遅れている感じで、`github` で `qwc-services/qwc-db-auth` の `README` を読んだり、`docker-compose.yml` のコメントを読んだりする必要があります。

また、`google` や `SNS` サービスにユーザ認証を移譲する `OAuth` には未対応です。

### 1-2. ユーザ登録

そして、これは結構大きい問題だと思うのですが、ゲストが自らユーザ登録（またはユーザ登録の申請）をする機能が無いために、すべてのユーザを管理者が登録する必要があるようです。

まあ、`SNS` ではなく `GIS` なので、そんなに多くの人がユーザ登録を求めることは無いでしょうから、特に問題にならないかも知れません。

### 1-3. 権限管理

ユーザの権限管理については、いわゆる `RBAC (Role-Based Access Control)` の方式が採用されています。 

すなわち、リソースにアクセスする権限を直接ユーザに付与するのではなく、ロール（`Role` 役割）という仲介的なモデルに付与し、ユーザには一つまたは複数のロールを割り当てるという方式です。

`RBAC` の実装は細かいところでいろいろなバリエーションがありますが、`qwc-services` における `RBAC` の特徴は:

- 三層構造
    1. ユーザ（User）、グループ（Group）
        - ユーザは一つまたは複数のグループに属しうる
        - グループにも、ユーザにも、一つまたは複数のロールを割り当てることができる
    2. ロール（Role）
        - ネストせず、単一のフラットなレイヤを形成する
        - 一つまたは複数のリソースへのアクセス許可を付与される
    3. リソースへのアクセス許可（Permission）
        - リソースのタイプによってはネストする

と言ったところです。

マニュアルとして下記を参照します。
- [Managing Users, Resources and Permissions](https://qwc-services.github.io/master/configuration/ResourcesPermissions/)

#### 1-3-1. リソース（Resource）

アクセス許可（Permission）の対象となるリソース（Resource）は、下記の通りです。

- `Map` ... QGiS プロジェクトに対応する `WMS`
- `Layer` ... `Map` のレイヤ
    - `Attribute` ... `Map Layer` の属性（`WFS` 用）
- `Print template` ... QGIS プロジェクトの印刷テンプレート
- `Data` ... 編集用のデータ・レイヤ
    - `Attribute` ... `Data Layer` の属性
- `Data (create)` ... 地物新規作成用レイヤ
- `Data (read)` ... 地物情報読み取り用レイヤ
- `Data (update)` ... 地物情報更新用レイヤ
- `Data (delete)` ... 地物情報削除用レイヤ
- `Viewer task` ... 権限設定可能なビューワ・タスク
- `FeatureInfo service` ... 地物情報サービス
- `FeatureInfo layer` ... 地物情報レイヤ
    - `Attribute` ... `FeatureInfo layer` の属性

##### 1-3-1-1. `Map` リソース

`map` リソースの名前は、`qgs-resources` ディレクトリからの QGIS プロジェクトの相対パス（ただし拡張子を除く）で指定します。例えば、QGIS プロジェクトが `qgs-resources/scan/isg.qgs` であれば、Map リソースの名前は `scan/isg` とします。

`layer` および `attribute` リソースの名前は、そのプロジェクトで指定したレイヤの「短い名前」および「フィールド名」です。ただし、フィールド名にエイリアスを指定している場合は、エイリアスが優先されます。

どういう `map`, `layer`, `attribute`, `print template` のリソースにアクセス出来るかは、`WMS` の `GetProjectSettings` および QGIS プロジェクトによって決定されます。

##### 1-3-1-2. `Data` リソース

`data` とその `attribute` のリソースは、`Data service` のためのデータ・レイヤを定義するものです。

詳細な `CRUD` 許可のために、`data` の代りに `data_create`, `data_read`, `data_update` および `data_delete` を使う事が出来ます。（ `data` + `write=false` は、`data_read` と同義であり、 `data` + `write=true` は `CRUD` 全てと同義です）

##### 1-3-1-3. `Viewer task` リソース

`viewer_task` リソースは、ビューワの機能（例えば印刷やラスタ・エクスポート）について、`RBAC` で許可したり禁止したりするものを指定するものです。

`viewer_task` の名前は、QWC2 の `config.json` における次のものに合致するように指定します。

- `menuItems` および `toolbarItems` の `key`
- プラグインの `name`
- `TaskButton` の `task`

`mode` を有する機能については、機能名とモード名を連結して機能を限定することが出来ます。例えば、`Identify` 機能には `Point` と `Region` のモードがありますが、名前を `IdentifyPoint`, `IdentifyRegion` とすれば、`Point` モードと `Region` モードを個別に権限管理することが出来ます。

アクセスを禁止されたビューワの機能はメニューとツールバーから削除されます。

リソースとして明示的に指定されていないビューワの機能は影響を受けません。

#### 1-3-2. アクセス許可（Permission）

リソースへのアクセス許可は、ロール（Role）に対して付与します。

`write` フラグは `data` リソースだけに適用され、データ・レイヤが `read-only` かどうかを決定します。

#### 1-3-4. ロール（Role）

初期状態では、`admin` と `public` という二つのロールが定義されています。

##### 1-3-4-1. Admin Role

名前は同じですが、ユーザとしての `admin` と、ロールとしての `admin` は区別されます。

管理の必要上、`admin` ロールにはすべてのリソースに対するアクセス許可を付与する必要があります。

:::note alert
`admin` のロールを削除してはいけません。削除すると、誰一人として管理画面にアクセス出来るユーザがいなくなります。

また、名前を変更することも出来ません。
:::

:::note
ユーザとしての `admin` は、`admin` ロールを割り当てられたユーザが他に存在するのであれば、削除しても構いません。セキュリティ上は、推測しやすい `admin` という名のユーザを残さない方が望ましいでしょう。
:::

##### 1-3-4-2. Public Role

`public` は、ログインしているか、ログインしていないかに関係なく、すべてのユーザに黙示的に割り当てられる特殊なロールです。

すなわち、誰に対しても与えることが出来るアクセス許可は `public` ロールに付与すれば良いということです。

:::note warn
`public` のロールを削除したり名前を変更したりすると、ゲスト・ユーザ（ログインしていないユーザ）に権限を付与することが出来なくなります。
:::

### 1-4. アクセス許可のデフォルト設定

`tenantConfig.json` の `permissions_default_allow` を設定すると、リソースとして登録されていない `map` や `layer` に対するアクセス許可のデフォルト動作を指定することが出来ます。

- `permissions_default_allow=true` ... リソースとして登録されていない `map` や `layer` はアクセスを許可される
- `permissions_default_allow=false` ... リソースとして登録されていない `map` や `layer` はアクセスを禁止される

:::note
一般的には `true` に設定する方が `RBAC` 階層構造データの保守が容易になります。`qwc-docker` で `qwc-services` をインストールした場合も、`true` に設定されています。
:::

```json:tenantConfig.json
{
  ...
  "config": {
    ...
    "permissions_default_allow": true,
    ...
  }
}
```

### 1-5. 許可されていないテーマの取扱い

許可されていないテーマをテーマ・スイッチャーにおいてどのように扱うかについては、`tenantConfig.json` の `mapViewer` サービス構成において、以下のように構成することが出来ます。

```json:tenantConfig.json
{
  ...
  {
    "name": "mapViewer",
    "config": {
      ...
      "show_restricted_themes": false,
      "show_restricted_themes_whitelist": [],
      "redirect_restricted_themes_to_auth": false,
      "internal_permalink_service_url": "http://qwc-permalink-service:9090"
    }
  }
}
```

- `"show_restricted_themes"` ... 許可されていないテーマのプレースホルダを表示するか否か
    - 既定値は `false`
- `"show_restricted_themes_whitelist"` ... 許可されていないテーマで、プレースホルダを表示するもののリスト
    - `"show_restricted_themes"` が `true` の場合のみ参照される
    - 既定値は空のリスト（`[]`）で、すべてのテーマが表示されることを意味する
- `"redirect_restricted_themes_to_auth"` ... ログインしていない状態で許可されていないテーマにアクセスしようとした場合に、ログイン画面にリダイレクトするか否か
    - 既定値は `false`
- `"internal_permalink_service_url"` ... ログイン画面にリダイレクトする場合に、解決された永続リンクからテーマを取得するための、内部的な永続リンク・サービスの URL
    - `"redirect_restricted_themes_to_auth"` が `true` で、`permalink_service_url` が指定されている場合にのみ参照される
    - 既定値は `http://qwc-permalink-service:9090`
        - `qwc-docker/api-gateway/nginx.conf` で指定されている URL
    - この項目、マニュアルが何を言ってるんだか、よくわからん

### 1-6. ユーザのグループ登録

マニュアルによると、オプションの `Registration GUI` をインストールすると、ユーザがグループへの登録やグループからの離脱を申請することが出来るようになるとのことです。

`2025-lts` にはまだ含まれていないのか、指示通りにしても動作しないようですし、たとえ動作してもあまり意味のある機能であるとは思えませんので、ここでは説明を割愛します。

## 2. 管理画面

### 2-1. Users

トップバーのコマンド・ボタンで左から二番目の `[Users]` を選択すると、次のようなユーザ一覧画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/000965d4-0811-48ad-bd38-e635777d06f6.png)

初期状態では `admin` ユーザのみが登録されています。

#### 2-1-1. User の追加

`[+ New User]` ボタンを押すと、次のような画面になって、新しいユーザを登録することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/9b031b7b-80d4-45da-8f61-2fa7092adba1.png)

| 項目 | 説明 | 備考 |
|---|---|---|
| User name  | ユーザ名 | = ログイン ID  |
| Description | 説明 | 省略可 |
| Email | メール・アドレス | 省略可 |
| Password | パスワード |   |
| Repeat Password | パスワード | 確認用 |
| Assigned groups | 所属グループ | |
| Assigned roles | 割り当てられたロール |   |

- グループとロールは、左側に選択候補のリスト、右側に選択済みのリストが表示され、クリックすると項目が左右に移動する
- グループとロールは後から変更できるので、今は気にしなくても大丈夫

#### 2-1-2. User の登録内容編集

`[(鉛筆) Edit]` ボタンを押すと、既存ユーザの登録内容を編集することが出来ます。画面の中身は登録画面と同じです。

#### 2-1-3. User の削除

`[× Remove]` というボタンを押すと、確認の上で、ユーザを削除することが出来ます。

:::note warn
ユーザとしての `admin` は、`admin` ロールを割り当てられたユーザが他に存在するのであれば、削除しても構いません。
:::

### 2-2. Groups

トップバーのコマンド・ボタンで `[Groups]` を選択すると、次のようなグループ一覧画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/0c1b36d7-89c3-4cb5-9cd0-5700822e0be3.png)

初期状態ではグループが一つも登録されていません。

:::note
想定されるユーザ数が非常に少ない場合は、無理にグループを作る必要はありません。
:::

#### 2-2-1. Group の追加

`[+ New Group]` ボタンを押すと、次のような画面になって、新しいグループを登録することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/9b33b884-b3ee-4431-b974-8ed5cbd3d022.png)

| 項目 | 説明 | 備考 |
|---|---|---|
| Name | グループ名 |  |
| Description | 説明 | 省略可 |
| Assigned users | 所属するユーザ | |
| Assigned roles | 割り当てられたロール |   |

- ユーザとロールは、左側に選択候補のリスト、右側に選択済みのリストが表示され、クリックすると項目が左右に移動する

上の図では、`b-member` という集落の役員会のグループを作って、`user-c`, `user-d`, `user-e` を所属させています。

#### 2-2-2. Group の登録内容編集

`[(鉛筆) Edit]` うボタンを押すと、既存グループの登録内容を編集することが出来ます。画面の中身は登録画面と同じです。

#### 2-2-3. Group の削除

`[× Remove]` ボタンを押すと、確認の上で、グループを削除することが出来ます。

:::note warn
一人でもユーザが所属しているグループを削除しようとするとエラーになります。
:::

### 2-3. Roles

トップバーのコマンド・ボタンで `[Roles]` を選択すると、次のようなロール一覧画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/316f114b-4d19-408a-af88-6e308ef1bdf6.png)

初期状態では、`admin` と `public` という二つのロールが登録されています。

:::note warn
`admin` ロールは削除したり名前を変更したりしてはいけません。
`public` ロールも削除したり名前を変更したりしない方が良いでしょう。
:::

#### 2-3-1. Role の追加

`[+ New Role]` ボタンを押すと、次のような画面になって、新しいロールを登録することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/60f6c0ff-ee2d-4cd7-8f8b-9ca5f4ec1972.png)

| 項目 | 説明 | 備考 |
|---|---|---|
| Name | ロール名 |  |
| Description | 説明 | 省略可 |
| Assigned groups | このロールを割り当てられたグループ |   |
| Assigned users | このロールを割り当てられたユーザ | |

- グループとユーザは、左側に選択候補のリスト、右側に選択済みのリストが表示され、クリックすると項目が左右に移動する

#### 2-3-2. Role の登録内容編集

`[(鉛筆) Edit]` ボタンを押すと、既存ロールの登録内容を編集することが出来ます。画面の中身は登録画面と同じです。

#### 2-3-3. Role の削除

`[× Remove]` ボタンを押すと、確認の上で、ロールを削除することが出来ます。

ロールを削除しても、ロールを割り当てられたグループやユーザが削除されることはありません。

ただし、ロールに付与されていた許可（Permission）はすべて一緒に削除されます。

### 2-4. Resources

トップバーのコマンド・ボタンで `[Resources]` を選択すると、次のようなリソース一覧画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/3f75fa16-2262-40d8-a5cb-f595549df1d3.png)

初期状態では、上のように、デモ用のリソースが登録されています。

`[(注意) Check unused]` ボタンを押すと、使用されていないリソースに `(注意)` マークが付きます。これらは残しておいても意味が無いので、チェック・ボックスで選んで `[× Remove selected]` ボタンで削除しても構いません。

`"Search facet"` タイプの `"ne_10m_admin_0_countries"` というリソースが残りますが、これも身に憶えの無いものですので、削除して差し支えないでしょう。

要するに、全部削除します。

#### 2-4-1. Resource の追加

`[+ New Resource]` ボタンを押して手作業でリソースを追加することも可能ですが、それよりも、`[Import maps]` ボタンを押して、現在使用しているテーマを `"map"` リソースとして追加する方が確実です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/e84df38a-afd9-4e95-9131-00edd42e8078.png)

上の図のように `"scan/isg"` という `"map"` リソースが追加されました。

#### 2-4-2. Role の登録内容編集

`[(鉛筆) Edit]` ボタンを押すと、既存リソースの登録内容を閲覧・編集することが出来ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/08dbf660-af84-4677-afc4-2c40ed9dab71.png)

| 項目 | 説明 | 備考 |
|---|---|---|
| Title | リソースのタイプ | Title はタイポ、Type が正しい |
| Name | リソース名 |  |
| Parent resource | 親リソース |   |

:::note warn
名前が変更出来る入力フォームですが、`[Import maps]` ボタンなどで自動的に登録されたリソースの名前を変更してはいけません。
:::

:::note
`[Import layers]` ボタンを押すと、この `"map"` リソースの子リソースである `"layer"` リソースをインポートすることが出来ますが、今は何もせずに先に進みます。
:::

#### 2-4-3. 許可（Permission）の追加

`[+ New Permission]` ボタンを押すと、下の図のように、許可（Permission）を新規登録する画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/f6c88170-8fc2-46ac-a4fa-37630df686a9.png)

| 項目 | 説明 | 備考 |
|---|---|---|
| Role | ロール名 |  |
| Resource | リソース名 |  |
| Priority | 優先度 | 0 以上の数値（既定値は 0）  |
| Write | 編集許可 | |

- `Priority` は空白のままでよい
- `Write` は `Data` タイプのリソースでのみ参照される

あらかじめリソースとして `"scan/isg"` が選ばれていますので、許可を付与するロールをドロップダウンで選択して `[Save]` ボタンを押します。

これによって、選択されたロール（上の図では `admin`）に対して、`"scan/isg"` `map` リソースにアクセスする許可が付与されたことになります。

#### 2-4-4. Resource のインポート

`[+ Import Resources]` ボタンを押すと、この `"map"` リソースの子リソースである `"Layer"` あるいは `"Data"` リソースをインポートすることが出来ますが、今は何もせずに先に進みます。

#### 2-4-5. Resource の削除

`[× Remove]` ボタンを押すと、確認の上で、リソースを削除することが出来ます。

このとき、リソースと関連付けられた許可（Permission）もすべて削除されます。

### 2-5. Permissions

トップバーのコマンド・ボタンで `[Permissons]` を選択すると、次のような許可（Permission）一覧画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/8fe77cf3-60ad-40d1-a661-2a2d3cf5d954.png)

#### 2-5-1. Permission の追加

#### 2-4-3. 許可（Permission）の追加

`[+ New Permission]` ボタンを押すと、許可（Permission）を新規登録する画面になります。リソース一覧画面から呼び出したのと同じ画面です。

| 項目 | 説明 | 備考 |
|---|---|---|
| Role | ロール名 |  |
| Resource | リソース名 |  |
| Priority | 優先度 | 0 以上の数値（既定値は 0）  |
| Write | 編集許可 | |

- `Priority` は空白のままでよい
- `Write` は `Data` タイプのリソースでのみ参照される

許可を付与するロールと対象になるリソースを選んで `[Save]` ボタンを押します。

#### 2-4-2. Permission の登録内容編集

`[(鉛筆) Edit]` ボタンを押すと、既存の許可（Permission）の登録内容を閲覧・編集することが出来ます。

画面の中身は登録画面と同じです。

#### 2-4-3. Permission の削除

`[× Remove]` ボタンを押すと、確認の上で、許可（Permission）を削除することが出来ます。

このとき、許可（Permission）と関連付けられていたロールとリソースは削除されません。

### 2-5. ビューワの再構成

権限管理の構成が完了したら、`[Home]` ボタンを押してホーム画面に戻り、`[Generate service configration]` ボタンを押して、ビューワを再構成します。

### 2-6. 動作確認

`"scan/isg"` `map` リソースを定義し、その許可（Permission）を `"admin"` ロールだけに付与した状態でビューワを再構成し、ビューワにアクセスしてみます。

- ゲスト・ユーザ（ログインしていないユーザ）には `"scan/isg"` が表示されない
- `"admin"` ロールを持つユーザでログインすると `"scan/isg"` が表示される

という結果になれば成功です。

## 3. クックブック

基本的な仕組みが分ったら、後はニーズに合わせて `RBAC` 階層構造を作成すれば良いのですが、いくつか典型的なユースケースを想定して、その設定手順を確認します。

### 3-1. 特定のレイヤのみを `public` から隠す

`"scan/isg"` の中の `"bld"` レイヤを `public` には見えないようにします。

#### 3-1-1. リソース設定

次の二つをリソースとして登録します。

- `"scan/isg"` ... `Map` リソース
- `"bld"` ... `Layer` リソース

`"scan/isg"` は既に登録済みですので、`"scan/isg"` の中に含まれる `"bld"` というレイヤをリソースとして新規に登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/9e35d032-0d5f-4fcd-bc9a-f3863e0b062f.png)

- `Title` (`Type`) ... Layer を選択
- `Name` ... レイヤ名 `"bld"` を入力
- `Parent resource` ... `"scan/isg"` を選択

`[Save]` ボタンを押すとリソース一覧の画面に戻ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/991f1804-3573-4ab9-a36d-a3b07524d3e5.png)

`"scan/isg"` `Map` リソースの子として `"bld"` `Layer` リソースが登録されているのが分ります。

:::note warn
`Layer` リソースが一覧に表示されない場合は、`[Type Filter]` が `All` になっていることを確認してください。
:::

#### 3-1-2. 許可（Permission）設定

次の二つの許可（Permisiion）を登録します。

- `"public"` ロール --- `"scan/isg"` `Map` リソース
- `"admin"` ロール --- `"bld"` `Layer` リソース

`"public"` ロールに `"scan/isg"` へのアクセスを許可しているため、`"admin"` ロールに `"scan/isg"` へのアクセスを明示的に許可する必要はありません。

#### 3-1-3. レイヤ・リソースの自動登録

権限管理の対象となるレイヤの数が多い場合は、`Map` リソースの編集画面から `[Import layers]` ボタンを押して、子のレイヤ・リソースを一括自動登録することが可能です。

この方法には、名前も親子関係も正しく設定されるという利点があります。

権限管理の対象としないレイヤは、`[Remove selected]` ボタンを使って削除すればオーケーです。

### 3-2. 特定の機能が利用できるロールを限定する

次の表のように、機能とロールの関係を設定したいとします。

| 機能 | リソース名 | `public` | `user` | `editor` | `admin` |
|----|----|:---:|:---:|:---:|:---:|
| ブックマーク | `Bookmark` | × | ○ | ○ | ○ |
| 地図をエクスポート | `MapExport` | × | × | ○ | ○ |
| 赤線引き | `Redlining` | × | × | × | ○ |
| 編集 | `Editing` | × | × | × | ○ |
| 地物フォーム | `FeatureForm` | × | × | × | ○ |
| 属性テーブル | `AttributeTable` | × | × | × | ○ |
| ルート探索 | `Routing` | × | × | × | ○ |
| ヘルプ | `Help` | × | × | × | ○ |

- リソース名 ... `viewer_task` または `plugin` リソース名
    - `menuItems` および `toolbarItems` の `key`
    - `TaskButton` の `task`
    - プラグインの `name`
- `public`, `user`, `editor`, `admin` ... ロール名
    - `user` ... 一般利用者用ロール（新規作成）
    - `editor` ... 編集機能をサポートするロール（新規作成）
- 「赤線引き」以下の編集関連機能はよく知らないので当面 `admin` のみに許可
- 「ヘルプ」も、操作説明をまだ書いていないので、同様

#### 3-2-1. RBAC ダイアグラム

上記の要求は割と簡単に見えますが、RBAC ダイアグラムを描いて整理してみると、思っていた以上に複雑な関係を作成する必要があることが分ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/fb8f5d9c-8a80-42dc-8356-f3cfc195ad25.png)

ここでは、グループを使っていますが、グループを使わなくても同じ効果をもつ `RBAC` ダイアグラムは構築することは可能です。要は、ユーザから矢印をたどって適切なリソースに行き着くことが出来るか出来ないかが問題です。

ただし、グループを使わない場合は、ユーザとロールの間の矢印を増やすか、または、ロールとリソースの間の矢印を増やすかして、適切な経路を設定しなければなりません。

:::note warn
グループを使わない場合でも、ロールとリソースの間の矢印、すなわち許可（Permission）は「一対多」の関係に保つ方が、保守性が良くなります。許可の階層で「多対多」の多数の矢印を使うと、リソースの数が増えるにつれて、ほんとうに訳が分らなくなります。ユーザとロールの間の矢印、すなわちユーザへのロール割当を「多対多」にして数を増やす方がだいぶマシです。
:::

:::note
グループを使うと、上のダイアグラムのように、グループとロールの間だけを「多対多」の関係にし、残りは「一対多」の関係にすることが出来ます。結果的に、矢印の数も総体として少なくなりますし、可読性と保守性も高まるのでお奨めです。
:::

なお、矢印の引き方によっては、ユーザからリソースに行き着くための経路が複数出来てしまう場合があります。例えば、上のダイアグラムでは、自分で決めた約束事にそむいて、一つのリソースの許可を複数のロールに付与したり、ユーザを複数のグループに所属させたり、ユーザに直接ロールを付与したりすると、複数の経路が出来てしまいます。しかし、そうなっても、動作上の問題は生じない筈です。まあ、ちょっと恥ずかしいので人には見せられなくなりますけれど。

どちらにしても、`RBAC` ダイアグラムは保守のために是非とも作成すべきです。`RBAC` は柔軟な反面、煩雑になりがちですので、ダイアグラムを描いておかないとすぐに訳が分らなくなります。

#### 3-2-2. ユーザ、グループ、ロールの設定

上記のダイアグラムに基づいて、ユーザ、グループ、ロールを追加し、その間の矢印（ユーザのグループ所属とグループへのロール割当）を設定します。

#### 3-2-2. リソース設定

上記の表に列挙したリソースを登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/fa5b5de9-79d4-4ae0-ad9f-0c1bb976aa31.png)

- Type ... 通常は `Viewer task`
- Name ... リソース名

#### 3-2-3. 許可（Permission）設定

`RBAC` ダイアグラムに基づいて、リソースをロールに許可する Permission を作成します。

#### 3-2-4. 「ルート探索」はうまく行かない

「ルート探索」機能は `Viewer task` タイプのリソースを登録すると、メニュー項目からは消えますが、マップ上で右クリックした場合に表示される情報ダイアログにルート探索用のボタンが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12310/31cabe83-ffd0-44f1-bb46-c7c3d58073d3.png)

`Plugin` タイプのリソースも同名で追加登録してみても、やはり上の図のようになります。

訳が分りません。

今のところ、運用環境においては `config.json` で削除して封印するしか無さそうです。

#### 3-2-4. 赤線引き（復活させる）

「赤線引き」`Redlining` については既に一度検討しました。

- [QGIS データを Web で表示 #11 - QWC2（終り）](https://qiita.com/softark/items/b4b36e24b49dc10280a0) > [1-13-4. 赤線引き](https://qiita.com/softark/items/b4b36e24b49dc10280a0#1-13-4-赤線引き)

これは `qwc-services` に依存しない機能で、スタンドアロンの `QWC2` でも利用できます。

機能としては、一時的なレイヤを作成して図形や文字を描画し、元からあるレイヤと重ねて表示する機能です。元の QGIS データを改変しないので、一時的な作業やプレゼンテーションに向いています。

この機能で作成したレイヤのデータはビューワを終了したり、テーマを読み込んだりすると失われます。

再利用の予定がある場合は、`KML` または `GeoJSON` としてエクスポートすることが出来ます。エクスポートしたレイヤのデータは、レイヤ・ツリーにある「レイヤをインポート」機能を使って読み込むことが出来ます。

一般の人にはベクタ・データの描画というだけで結構敷居が高くなりますから、スタンドアロン環境の `QWC2` ではこの機能をメニューから隠してしまっても構わないと思います。しかし、ある程度のスキルを持ったユーザにとっては便利な機能ですので、ユーザ認証と権限管理が可能な `qwc-services` 環境下ではロールを限定して開放するのが適切でしょう。

なお、用語は `Redlining` を直訳した「赤線引き」から「スケッチ」などに改めるのが適切でしょう。

```diff_json:ja-JP.json
    {
      "locale": "ja-JP",
      "messages": {
        ...
        "appmenu": {
          "filter": "メニューをフィルタ...",
          "items": {
            ...
            "PrintScreen3D": "ラスタ・エクスポート",
-           "Redlining": "赤線引き",
+           "Redlining": "スケッチ",
            "Routing": "ルート探索",
            ...
          },
          "menulabel": "地図 & ツール"
        },
        ...
        "redlining": {
          ...
          "layer": "レイヤ",
-         "layertitle": "赤線引き",
+         "layertitle": "スケッチ",
          "line": "線",
          ...
        },
        ...
      }
    }
```

## And so, what's next?

次回は編集機能を使うために必要となるデータベース環境 `PostGIS` をセットアップします。

- [qwc-services による Web GIS の構築 #3 PostGIS](https://qiita.com/softark/items/74861df6a6ebfd359eaa)