GeneXus Access Manager(GAM) #5　GAMを使用したメニューの定義・利用

[GeneXus Access Manager(GAM) #4 GAM Authorization](https://qiita.com/sgtrducky/items/c55500d1296039357b72) にてGAMのAuthorizationの概要を確認ました。実行時のPermissionのチェックだけでなく、Permissionあるいはそれらを束ねたRollに基づいてメニューの出し分けをする機能が提供されているようです。

# メニューの定義
- [GAM を使用してメニューを定義する方法 (wiki.genexus.jp)](http://wiki.genexus.jp/hwiki.aspx?GAM+%e3%82%92%e4%bd%bf%e7%94%a8%e3%81%97%e3%81%a6%e3%83%a1%e3%83%8b%e3%83%a5%e3%83%bc%e3%82%92%e5%ae%9a%e7%be%a9%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95,)
- [Howto: Define a Menu using GAM (wiki.genexus.com)](https://wiki.genexus.com/commwiki/servlet/wiki?29681,Howto%3A+Define+a+Menu+using+GAM)

にGAMBackendアプリでメニューデータを定義する方法が説明されています。
Settings > APPLICATIONS から
![GAM01.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/d97b0807-96d4-fddd-8430-5f33f67812d9.jpeg)

アプリを指定してMenus　と辿ってメニュー定義用の画面に遷移します。

![GAM02.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/d2286d83-de2b-222e-7b2c-d719ac89adb1.jpeg)

ざっくりいえば、MenusデータとOptionsデータに必要な内容を定義していくイメージです。Optionには起動するオブジェクトだけでなく、Menuデータを再帰的に定義できるので、サブメニュー等を表現できます。
上述したGAMBackendアプリケーションのメニュー：

- USERS
- ROLES
- SETTINGS
    - SECURITY POLICIES
    - APPLICATIONS
    - REPOSITORY CONFIGURATIONS
    - ・・・

自体が GAMのメニューで定義されていますのでこれを見るとわかりやすいです。
![GAM03.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/b52a14ae-6230-345d-6634-1d67d33f607c.jpeg)

GAMBackendMainMenuのOptionsは以下のOptionを含み、UsersとRolesのTypeがSimple、SettingsのTypeがMenuになっていることが見て取れます。
![GAM04.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/95109486-01f6-604f-ebc1-e70c3ab66d86.jpeg)

Users、Settingsの定義内容をそれぞれ見てみるとOption TypeがSimpleであるUsersの方は呼び出すResourceと許可するPermissionを、Option TypeがMenuであるSettingsの方は、上のMenusの一覧に表示されていた別のメニュー（GAMBackendSettingsMenu）を指定しています。
![GAM05.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/bb856803-9ed6-cd5f-6834-f9b0162e88e9.jpeg)

Usersの方のResource呼び出しですが、[GeneXus Access Manager(GAM) #4 GAM Authorization](https://qiita.com/sgtrducky/items/c55500d1296039357b72)  で見ました「実行時の自動的チェック」の仕組みでResource（Webパネルとか）側に定義された必要Permission（Permission Prefixプロパティ）により、遷移させてチェックするのでもよいのでしょうが、ここにPermissionを定義することで、メニュー自体の出し分けに使える（後述）ものと理解。
あとResource Parametersが定義できるようで、同じResourceを別パラメータで別メニューに定義して呼び出し時の挙動制御に使えそうですね。

# メニュー表示概要
- [JSCookMenu ユーザーコントロールを使用して GAM メニューを表示する方法 (wiki.genexus.jp)](http://wiki.genexus.jp/hwiki.aspx?JSCookMenu+%e3%83%a6%e3%83%bc%e3%82%b6%e3%83%bc%e3%82%b3%e3%83%b3%e3%83%88%e3%83%ad%e3%83%bc%e3%83%ab%e3%82%92%e4%bd%bf%e7%94%a8%e3%81%97%e3%81%a6+GAM+%e3%83%a1%e3%83%8b%e3%83%a5%e3%83%bc%e3%82%92%e8%a1%a8%e7%a4%ba%e3%81%99%e3%82%8b%e6%96%b9%e6%b3%95)
- [Howto: Display a GAM Menu using Jscookmenu UC (wiki.genexus.com)](https://wiki.genexus.com/commwiki/servlet/wiki?29743,Howto%3A+Display+a+GAM+Menu+using+Jscookmenu+UC)

↓こちらではTreeViewユーザーコントロールを使用した説明になっていますね。

- [GAMで作成したユーザーの権限に基づいて表示するメニュー内容を変えたい (GX collabo DB)](http://www.gxsupport.jp/gxfaq/faqdisplay.aspx?2885)

使用しているGeneXus17のTrialではTreeViewユーザーコントロールがデフォルトで使えるのでこちらで確認してみます。

## TreeView ユーザコントロール

Webパネル等にこのユーザコントロールを適用しますと、必要なSDT（TreeNodeCollection）がナレッジベースにインポートされて、当該WebパネルではそれをTypeに持った変数、及びEventにサンプルコードが設定されます。ドキュメントもありますね。

- [Treeview コントロール (wiki.genexus.jp)](http://wiki.genexus.jp/hwiki.aspx?Treeview+%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%AB,)
- [Treeview Control (wiki.genexus.com)](https://wiki.genexus.com/commwiki/servlet/wiki?5055,Treeview+Control)

なのでGAMのAPIでメニューデータを取り（その際Permissionによるフィルタをかけ、権限のないメニューを取ってこない）、それをTreeNodeCollectionに設定するということですね。

# メニュー表示実機検証

上掲のcollabo DBでは1つのMenuとその直下にぶら下がるOptionsの簡易な例ですので、ここではまずMain Menuを取り、その配下はOption TypeがMenuである再帰的な構造も含めてTreeViewユーザコントロール用のTreeNodeCollectionに移送する検証を行います。

## 取得するMenu/Optionsデータ

Menuデータは以下のようにしました。
![GAM06.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/9009bf61-8ead-df9d-47bd-9b61a9d20faa.jpeg)

ApplicationのMain Menuは、WpAuthXXに設定します。
![GAM07.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/66f8d622-6980-bbd0-0b81-b3cb8d04af9f.jpeg)

WpAuthXXのOptionsにはType=MenuでWpAuth0XとWpAuth1Xをぶら下げます。
![GAM08.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/bd04d6d8-8418-30bb-69b5-c38cbb52b9f0.jpeg)
WpAuth0XとWpAuth1XのOptionsにはType=Simpleで、個別の画面WPAuth00/01/02、WpAuth10/11/12をそれぞれ設定。Permissionとして、0X系のMenuにはwpauth0x_Execute、1X系のMenuにはwpauth1x_Executeを設定。

## User データ
testuser00にはwpauth0x_Execute、wpauth1x_Executeの両方を、testuser10にはwpauth1x_Executeのみ付与し、ログイン時に表示されるメニューの差異を確認します。

## 処理
上掲collabo DBの例では

```
&GAMApplicationMenuCollection = &GAMApplication.GetMenus(&GAMApplicationMenuFilter,&GAMErrors)
&GAMApplicationMenu = &GAMApplicationMenuCollection.Item(1)
```

として、&GAMApplicationMenuCollectionの1つ目の要素について処理をしています。&GAMApplicationMenuのコレクションをGetMenusで取りますと、そのGAMApplication配下のMenuが全て（本来他のMenuの配下にぶら下がるMenuも）取れてしまいます。1つ目がMainという決め、というのも何ですので、上記で設定しましたApplicationのMain Menu属性を利用して、以下のようにしてみました。

```
// Get Application
&GAMApplication = GAMApplication.Get()
	
// Get Main Menu
&GAMApplicationMenu = &GAMApplication.GetMenu(&GAMApplication.MainMenuId, &GAMErrorCollection)
```

あとはメニューのオプション（GAMMenuOptionList）を取得していきますが、これはGAMOptionList.Nodes（GAMOptionListのコレクション）を再帰的に持ちます。これをTreeViewのTreeNodeCollectionに移送するために以下のようなProcedure（PrGAMMenuOptionToTreeNode(inGAMMenuOptionListNodes : GAMMenuOptionListのコレクション, outTreeNode : TreeNodeのコレクション )を作成しました。

```
For &GAMMenuOptionList In &inGAMMenuOptionListNodes
	&treeNode = New()
	&treeNode.Id = &GAMMenuOptionList.Id.ToString()
	&treeNode.Name = &GAMMenuOptionList.Name
	&treeNode.Link = &GAMMenuOptionList.Link
	
	If &GAMMenuOptionList.Nodes.Count > 0
		&treeNode.Nodes = PrGAMMenuOptionToTreeNode.Udp(&GAMMenuOptionList.Nodes)
	EndIf

	&outTreeNodeCollection.Add(&treeNode)
EndFor
```

これの呼び出しを先程のMain Menu取得後に加え、全体（とりあえずStart Eventに詰め込んでます）としては以下のように。

```
Event Start
	
	// Get Application
	&GAMApplication = GAMApplication.Get()
	
	// Get Main Menu
	&GAMApplicationMenu = &GAMApplication.GetMenu(&GAMApplication.MainMenuId, &GAMErrorCollection)
	&GAMMenuOptionList = GAMRepository.GetApplicationMenu(&GAMApplication.GUID, &GAMApplicationMenu.GUID, &GAMErrorCollection)
	
	&treeNode = new()
	&treeNode.Id = &GAMMenuOptionList.Id.ToString()
	&treeNode.Name = &GAMMenuOptionList.Name
	
	&treeNode.Nodes = PrGAMMenuOptionToTreeNode.Udp(&GAMMenuOptionList.Nodes)
	&treeNodeCollectionData.Add(&treeNode)
	
EndEvent
```

## ユーザ毎の画面の見え方

![GAM10.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/168717/4628aae0-8f38-939e-07dd-af4155e6214e.jpeg)



2021年08月06日　初版