前回は、QGIS Server と QGIS Web Client 2 (QWC2) を中核とする統合的 Web GIS エコ・システムである qwc-services を qwc-docker によってインストールし、NapCache とも連携させて、QGIS のプロジェクトを Web 地図として表示するところまでやりました。
現段階では、単体としての 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 の特徴は:
- 三層構造
- ユーザ(User)、グループ(Group)
- ユーザは一つまたは複数のグループに属しうる
- グループにも、ユーザにも、一つまたは複数のロールを割り当てることができる
- ロール(Role)
- ネストせず、単一のフラットなレイヤを形成する
- 一つまたは複数のリソースへのアクセス許可を付与される
- リソースへのアクセス許可(Permission)
- リソースのタイプによってはネストする
- ユーザ(User)、グループ(Group)
と言ったところです。
マニュアルとして下記を参照します。
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 ロールにはすべてのリソースに対するアクセス許可を付与する必要があります。
admin のロールを削除してはいけません。削除すると、誰一人として管理画面にアクセス出来るユーザがいなくなります。
また、名前を変更することも出来ません。
ユーザとしての admin は、admin ロールを割り当てられたユーザが他に存在するのであれば、削除しても構いません。セキュリティ上は、推測しやすい admin という名のユーザを残さない方が望ましいでしょう。
1-3-4-2. Public Role
public は、ログインしているか、ログインしていないかに関係なく、すべてのユーザに黙示的に割り当てられる特殊なロールです。
すなわち、誰に対しても与えることが出来るアクセス許可は public ロールに付与すれば良いということです。
public のロールを削除したり名前を変更したりすると、ゲスト・ユーザ(ログインしていないユーザ)に権限を付与することが出来なくなります。
1-4. アクセス許可のデフォルト設定
tenantConfig.json の permissions_default_allow を設定すると、リソースとして登録されていない map や layer に対するアクセス許可のデフォルト動作を指定することが出来ます。
-
permissions_default_allow=true... リソースとして登録されていないmapやlayerはアクセスを許可される -
permissions_default_allow=false... リソースとして登録されていないmapやlayerはアクセスを禁止される
一般的には true に設定する方が RBAC 階層構造データの保守が容易になります。qwc-docker で qwc-services をインストールした場合も、true に設定されています。
{
...
"config": {
...
"permissions_default_allow": true,
...
}
}
1-5. 許可されていないテーマの取扱い
許可されていないテーマをテーマ・スイッチャーにおいてどのように扱うかについては、tenantConfig.json の mapViewer サービス構成において、以下のように構成することが出来ます。
{
...
{
"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] を選択すると、次のようなユーザ一覧画面になります。
初期状態では admin ユーザのみが登録されています。
2-1-1. User の追加
[+ New User] ボタンを押すと、次のような画面になって、新しいユーザを登録することが出来ます。
| 項目 | 説明 | 備考 |
|---|---|---|
| User name | ユーザ名 | = ログイン ID |
| Description | 説明 | 省略可 |
| メール・アドレス | 省略可 | |
| Password | パスワード | |
| Repeat Password | パスワード | 確認用 |
| Assigned groups | 所属グループ | |
| Assigned roles | 割り当てられたロール |
- グループとロールは、左側に選択候補のリスト、右側に選択済みのリストが表示され、クリックすると項目が左右に移動する
- グループとロールは後から変更できるので、今は気にしなくても大丈夫
2-1-2. User の登録内容編集
[(鉛筆) Edit] ボタンを押すと、既存ユーザの登録内容を編集することが出来ます。画面の中身は登録画面と同じです。
2-1-3. User の削除
[× Remove] というボタンを押すと、確認の上で、ユーザを削除することが出来ます。
ユーザとしての admin は、admin ロールを割り当てられたユーザが他に存在するのであれば、削除しても構いません。
2-2. Groups
トップバーのコマンド・ボタンで [Groups] を選択すると、次のようなグループ一覧画面になります。
初期状態ではグループが一つも登録されていません。
想定されるユーザ数が非常に少ない場合は、無理にグループを作る必要はありません。
2-2-1. Group の追加
[+ New Group] ボタンを押すと、次のような画面になって、新しいグループを登録することが出来ます。
| 項目 | 説明 | 備考 |
|---|---|---|
| Name | グループ名 | |
| Description | 説明 | 省略可 |
| Assigned users | 所属するユーザ | |
| Assigned roles | 割り当てられたロール |
- ユーザとロールは、左側に選択候補のリスト、右側に選択済みのリストが表示され、クリックすると項目が左右に移動する
上の図では、b-member という集落の役員会のグループを作って、user-c, user-d, user-e を所属させています。
2-2-2. Group の登録内容編集
[(鉛筆) Edit] うボタンを押すと、既存グループの登録内容を編集することが出来ます。画面の中身は登録画面と同じです。
2-2-3. Group の削除
[× Remove] ボタンを押すと、確認の上で、グループを削除することが出来ます。
一人でもユーザが所属しているグループを削除しようとするとエラーになります。
2-3. Roles
トップバーのコマンド・ボタンで [Roles] を選択すると、次のようなロール一覧画面になります。
初期状態では、admin と public という二つのロールが登録されています。
admin ロールは削除したり名前を変更したりしてはいけません。
public ロールも削除したり名前を変更したりしない方が良いでしょう。
2-3-1. Role の追加
[+ New Role] ボタンを押すと、次のような画面になって、新しいロールを登録することが出来ます。
| 項目 | 説明 | 備考 |
|---|---|---|
| Name | ロール名 | |
| Description | 説明 | 省略可 |
| Assigned groups | このロールを割り当てられたグループ | |
| Assigned users | このロールを割り当てられたユーザ |
- グループとユーザは、左側に選択候補のリスト、右側に選択済みのリストが表示され、クリックすると項目が左右に移動する
2-3-2. Role の登録内容編集
[(鉛筆) Edit] ボタンを押すと、既存ロールの登録内容を編集することが出来ます。画面の中身は登録画面と同じです。
2-3-3. Role の削除
[× Remove] ボタンを押すと、確認の上で、ロールを削除することが出来ます。
ロールを削除しても、ロールを割り当てられたグループやユーザが削除されることはありません。
ただし、ロールに付与されていた許可(Permission)はすべて一緒に削除されます。
2-4. Resources
トップバーのコマンド・ボタンで [Resources] を選択すると、次のようなリソース一覧画面になります。
初期状態では、上のように、デモ用のリソースが登録されています。
[(注意) Check unused] ボタンを押すと、使用されていないリソースに (注意) マークが付きます。これらは残しておいても意味が無いので、チェック・ボックスで選んで [× Remove selected] ボタンで削除しても構いません。
"Search facet" タイプの "ne_10m_admin_0_countries" というリソースが残りますが、これも身に憶えの無いものですので、削除して差し支えないでしょう。
要するに、全部削除します。
2-4-1. Resource の追加
[+ New Resource] ボタンを押して手作業でリソースを追加することも可能ですが、それよりも、[Import maps] ボタンを押して、現在使用しているテーマを "map" リソースとして追加する方が確実です。
上の図のように "scan/isg" という "map" リソースが追加されました。
2-4-2. Role の登録内容編集
[(鉛筆) Edit] ボタンを押すと、既存リソースの登録内容を閲覧・編集することが出来ます。
| 項目 | 説明 | 備考 |
|---|---|---|
| Title | リソースのタイプ | Title はタイポ、Type が正しい |
| Name | リソース名 | |
| Parent resource | 親リソース |
名前が変更出来る入力フォームですが、[Import maps] ボタンなどで自動的に登録されたリソースの名前を変更してはいけません。
[Import layers] ボタンを押すと、この "map" リソースの子リソースである "layer" リソースをインポートすることが出来ますが、今は何もせずに先に進みます。
2-4-3. 許可(Permission)の追加
[+ New Permission] ボタンを押すと、下の図のように、許可(Permission)を新規登録する画面になります。
| 項目 | 説明 | 備考 |
|---|---|---|
| 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)一覧画面になります。
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" というレイヤをリソースとして新規に登録します。
-
Title(Type) ... Layer を選択 -
Name... レイヤ名"bld"を入力 -
Parent resource..."scan/isg"を選択
[Save] ボタンを押すとリソース一覧の画面に戻ります。
"scan/isg" Map リソースの子として "bld" Layer リソースが登録されているのが分ります。
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 ダイアグラムを描いて整理してみると、思っていた以上に複雑な関係を作成する必要があることが分ります。
ここでは、グループを使っていますが、グループを使わなくても同じ効果をもつ RBAC ダイアグラムは構築することは可能です。要は、ユーザから矢印をたどって適切なリソースに行き着くことが出来るか出来ないかが問題です。
ただし、グループを使わない場合は、ユーザとロールの間の矢印を増やすか、または、ロールとリソースの間の矢印を増やすかして、適切な経路を設定しなければなりません。
グループを使わない場合でも、ロールとリソースの間の矢印、すなわち許可(Permission)は「一対多」の関係に保つ方が、保守性が良くなります。許可の階層で「多対多」の多数の矢印を使うと、リソースの数が増えるにつれて、ほんとうに訳が分らなくなります。ユーザとロールの間の矢印、すなわちユーザへのロール割当を「多対多」にして数を増やす方がだいぶマシです。
グループを使うと、上のダイアグラムのように、グループとロールの間だけを「多対多」の関係にし、残りは「一対多」の関係にすることが出来ます。結果的に、矢印の数も総体として少なくなりますし、可読性と保守性も高まるのでお奨めです。
なお、矢印の引き方によっては、ユーザからリソースに行き着くための経路が複数出来てしまう場合があります。例えば、上のダイアグラムでは、自分で決めた約束事にそむいて、一つのリソースの許可を複数のロールに付与したり、ユーザを複数のグループに所属させたり、ユーザに直接ロールを付与したりすると、複数の経路が出来てしまいます。しかし、そうなっても、動作上の問題は生じない筈です。まあ、ちょっと恥ずかしいので人には見せられなくなりますけれど。
どちらにしても、RBAC ダイアグラムは保守のために是非とも作成すべきです。RBAC は柔軟な反面、煩雑になりがちですので、ダイアグラムを描いておかないとすぐに訳が分らなくなります。
3-2-2. ユーザ、グループ、ロールの設定
上記のダイアグラムに基づいて、ユーザ、グループ、ロールを追加し、その間の矢印(ユーザのグループ所属とグループへのロール割当)を設定します。
3-2-2. リソース設定
上記の表に列挙したリソースを登録します。
- Type ... 通常は
Viewer task - Name ... リソース名
3-2-3. 許可(Permission)設定
RBAC ダイアグラムに基づいて、リソースをロールに許可する Permission を作成します。
3-2-4. 「ルート探索」はうまく行かない
「ルート探索」機能は Viewer task タイプのリソースを登録すると、メニュー項目からは消えますが、マップ上で右クリックした場合に表示される情報ダイアログにルート探索用のボタンが表示されます。
Plugin タイプのリソースも同名で追加登録してみても、やはり上の図のようになります。
訳が分りません。
今のところ、運用環境においては config.json で削除して封印するしか無さそうです。
3-2-4. 赤線引き(復活させる)
「赤線引き」Redlining については既に一度検討しました。
これは qwc-services に依存しない機能で、スタンドアロンの QWC2 でも利用できます。
機能としては、一時的なレイヤを作成して図形や文字を描画し、元からあるレイヤと重ねて表示する機能です。元の QGIS データを改変しないので、一時的な作業やプレゼンテーションに向いています。
この機能で作成したレイヤのデータはビューワを終了したり、テーマを読み込んだりすると失われます。
再利用の予定がある場合は、KML または GeoJSON としてエクスポートすることが出来ます。エクスポートしたレイヤのデータは、レイヤ・ツリーにある「レイヤをインポート」機能を使って読み込むことが出来ます。
一般の人にはベクタ・データの描画というだけで結構敷居が高くなりますから、スタンドアロン環境の QWC2 ではこの機能をメニューから隠してしまっても構わないと思います。しかし、ある程度のスキルを持ったユーザにとっては便利な機能ですので、ユーザ認証と権限管理が可能な qwc-services 環境下ではロールを限定して開放するのが適切でしょう。
なお、用語は Redlining を直訳した「赤線引き」から「スケッチ」などに改めるのが適切でしょう。
{
"locale": "ja-JP",
"messages": {
...
"appmenu": {
"filter": "メニューをフィルタ...",
"items": {
...
"PrintScreen3D": "ラスタ・エクスポート",
- "Redlining": "赤線引き",
+ "Redlining": "スケッチ",
"Routing": "ルート探索",
...
},
"menulabel": "地図 & ツール"
},
...
"redlining": {
...
"layer": "レイヤ",
- "layertitle": "赤線引き",
+ "layertitle": "スケッチ",
"line": "線",
...
},
...
}
}
And so, what's next?
次回は編集機能を使うために必要となるデータベース環境 PostGIS をセットアップします。















