プリザンターのユーザの権限を知る方法

## はじめに
プリザンターを使っていく上で、このサイトでこのユーザーってどの権限があるの？と調べたくなることがありませんか？
そんなときに便利に使えるSQLのクエリを紹介します。

:::note info
本記事はSQL Serverを前提としています。他のRDBMSを使用している場合は適時書き換えが必要になります。
:::

## 取得する方法
使用するクエリを紹介します。本クエリではサイトの管理の「アクセス権の管理」で設定した情報が取得出来ます。「レコードのアクセス制御」や「項目のアクセス制御」によるサイトより細かい粒度でのアクセス権の取得には対応していません。また、グループinグループについては階層の深さが可変のため現状では対応させていません[^1]。

```sql
SELECT
    [SiteId], 
    [PermissionType]
FROM
    ( 
        SELECT
            [Sites].[SiteId], 
            [Permissions].[PermissionType] 
        FROM
            [Sites] 
            LEFT JOIN [Permissions] 
                ON [Sites].[InheritPermission] = [Permissions].[ReferenceId] 
            LEFT JOIN [Depts] AS [Depts] 
                ON [Permissions].[DeptId] = [Depts].[DeptId] 
            LEFT JOIN [Users] AS [DeptsUsers] 
                ON [Depts].[DeptId] = [DeptsUsers].[DeptId] 
            LEFT JOIN [GroupMembers] AS [Groups] 
                ON [Permissions].[GroupId] = [Groups].[GroupId] 
            LEFT JOIN [Depts] AS [GroupsDepts] 
                ON [Groups].[DeptId] = [GroupsDepts].[DeptId] 
            LEFT JOIN [Users] AS [GroupsDeptsUsers] 
                ON [GroupsDepts].[DeptId] = [GroupsDeptsUsers].[DeptId] 
        WHERE
            ( 
                @UserId IN ([Permissions].[UserId], [DeptsUsers].[UserId], [GroupsDeptsUsers].[UserId], [Groups].[UserId])
            ) 
            AND [Sites].[SiteId] = @SiteId
    ) AS Query 
GROUP BY
    [SiteId],
    [PermissionType]
```
`@UserId`と`@SiteId`のパラメータの部分は調べたいユーザのユーザIDを対象となるサイトのサイトIDに置換してください。

## 実際に使ってみた
実際に当社の社内環境のサイトID:171783を例に結果を取りだしてみます。
権限をツリー化してみるとこんな感じになります。

```plantuml
@startjson
{
	"サイトID": 171783,
	"継承元": {
		"サイトID": 210,
		"権限": [
			{
				"組織": {
					"組織ID": 1,
					"ユーザID": [
						1,
						3,
						6,
						7,
						9,
						10,
						12,
						19,
						20,
						52,
						57,
						63,
						67,
						69,
						72,
						73,
						74,
						75,
						76,
						89,
						91,
						101,
						102,
						121,
						127,
						134,
						144
					]
				},
				"権限": 511
			},
			{
				"グループ": {
					"グループID": 7,
					"ユーザID": [
						66
					]
				},
				"権限": 63
			},
			{
				"グループ": {
					"グループID": 11,
					"ユーザID": [
						134
					],
					"組織": [
						{
							"組織ID": 6,
							"ユーザID": [
								38,
								40,
								42,
								46,
								49,
								53,
								59,
								68,
								70,
								77,
								80,
								84,
								104,
								106,
								107,
								108,
								109,
								110,
								111,
								112,
								113,
								122,
								123,
								124
							]
						},
						{
							"組織ID": 17,
							"ユーザID": [
								125,
								126,
								128,
								135,
								136,
								137,
								138,
								141,
								145,
								146
							]
						}
					]
				},
				"権限": 63
			},
			{
				"グループ": {
					"グループID": 12,
					"ユーザID": []
				},
				"権限": 63
			},
			{
				"ユーザID": 1,
				"権限": 255
			}
		]
	}
}
@endjson
```

サイトID:210から権限を継承しているうえに、グループに組織が入っていたりユーザーが入っていたりとかなりカオスな状態になっています。ここでユーザID:123を指定してデータを取り出してみます。
```json
{
    "SiteId":171783,
    "PermissionType":63
}
```
設定通りの権限が取得出来ていますね。

## PermissionTypeを読み解く
PermissionTypeはビットマスクで指定されています。設定は下記の通りです。
```cs
public enum Types : long
{
    NotSet = 0,                         // 00000000000000000000000000000000
    Read = 1,                           // 00000000000000000000000000000001
    Create = 2,                         // 00000000000000000000000000000010
    Update = 4,                         // 00000000000000000000000000000100
    Delete = 8,                         // 00000000000000000000000000001000
    SendMail = 16,                      // 00000000000000000000000000010000
    Export = 32,                        // 00000000000000000000000000100000
    Import = 64,                        // 00000000000000000000000001000000
    ManageSite = 128,                   // 00000000000000000000000010000000
    ManagePermission = 256,             // 00000000000000000000000100000000
    ManageTenant = 1073741824,          // 01000000000000000000000000000000
    ManageService = 2147483648,         // 10000000000000000000000000000000
}
```
> https://github.com/Implem/Implem.Pleasanter/blob/main/Implem.Pleasanter/Libraries/Security/Permissions.cs

取得したPermissionTypeを2進数化すれば設定されている権限が分かります。今回は63なので`0011 1111`となります。10進数で拾うと`1,2,4,8,16,32`です。それを上のビットマスクの設定と照らし合わすと`Read,Create,Update,Delete,SendMail,Export`となります。
ユーザに対して特定の権限が当てられているかどうかを調べることがほとんどだと思いますので、その場合は、ビット演算してしまえば一発で対応出来ます。
```cs
var permissionType = 63;
var delete = 8;

if ((permissionType & delete) == delete)
{
	Console.WriteLine("Delete権限あり");
}
else
{
	Console.WriteLine("Delete権限なし");
}
```
サンプルだとC#ですが他の言語でもビット演算は出来るので使用する言語に合わせて処理を書いてみてください。

## まとめ
ちょっとしたクエリでユーザの権限情報を取得することができました。拡張SQLにしてスクリプトと組み合わせるとサイトアイコンに読み取り専用マークを追加したりなど、いろいろとUX/UI関連で応用が効くので、是非活用してみてください。

[^1]:力業で対応出来ないこともないのですが、今回は省略しています。