RoleContributorでユーザのロールを更新する

こんにちは。今回はLiferay公式ブログの面白い記事を紹介しようと思います。

LiferayはRoleContributorというインターフェイスを提供しています。当該インターフェイスを実装するOSGIサービスを提供すると、ユーザのアクセスごとにユーザのロールを動的に変更することができます。

今回は「平日09:00 ~ 18:00」の間だけに、「Worktime Content Viewer」ユーザグループのメンバーが「Portal Content Viewer」ロールに付与される、というユーズケースを考えてみましょう。

RoleContributor

LiferayのPermissionCheckerの仕様により、DBからユーザのロールを取得後、osgiフレームワークに登録される全てのRoleContributorを利用し、取得されるロール配列へのロールの追加または削除ができます。

  • 追加/削除方式はRoleContributorのcontributeメソッドの引数であるRoleCollectionのaddRoleId/removeRoleIdメソッドを呼ぶ
  • RoleContributorはPermissionChecker.getRoleIds実行時に呼ばれるのため、リクエスト毎に実行される

@Component(
	immediate = true,
	service = RoleContributor.class
)
public class WorktimeRoleContributor implements RoleContributor {
	
	@Override
	public void contribute(RoleCollection roleCollection) {
		
		long[] userGroupIds = roleCollection.getUserBag().getUserUserGroupsIds();
		long companyId = roleCollection.getCompanyId();
		
		if (ArrayUtil.contains(userGroupIds, getWorktimeUsergroupId(companyId))) {
			
			if (!isWorktime()) {
				roleCollection.removeRoleId(getPortalContentRevRoleId(companyId));
			}
		}
	}
	
	private boolean isWorktime() {
		Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tokyo"));
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY
		 || cal.get(Calendar.HOUR_OF_DAY) < 9 || cal.get(Calendar.HOUR_OF_DAY) > 18) return false;
		return true;
	}
	
	// DBアクセスは一回のみ
	private long getWorktimeUsergroupId(long companyId) {
		if (worktimeUserGroupId < 0) {
            UserGroup userGroup = userGroupLocalService.fetchUserGroup(companyId, "Worktime Content Reviewer");
            worktimeUserGroupId = (userGroup == null) ? 0L : userGroup.getUserGroupId();
		}
		return worktimeUserGroupId;
	}
	
	// DBアクセスは一回のみ
	private long getPortalContentRevRoleId(long companyId) {
		
		if (pcrRoleId < 0) {
            Role role = roleLocalService.fetchRole(companyId, RoleConstants.PORTAL_CONTENT_REVIEWER);
            pcrRoleId = (role == null) ? 0L : role.getRoleId();
		}
		return pcrRoleId;
		
	}
	
	private static long worktimeUserGroupId = -1L;
	private static long pcrRoleId = -1L;
	
	@Reference
	private UserGroupLocalService userGroupLocalService;
	
	@Reference
	private RoleLocalService roleLocalService;
}

 

検証

ひとまず、「Worktime Content Reviewer」ユーザグループを作成し、「Portal Content Viewer」ロールにアサインします。

つづいて、screenName=「worktime_reviewer」のLiferayユーザを作成し、「Worktime Content Reviewer」ユーザグループをアサインします。

その後、以下の二つのwebコンテンツを作成してみましょう。

  • 「visible to Users」コンテンツの権限はデフォルトのままにする(「Guest」、「Site Member」は「View」権限を持つ)
  • 「visible to Reviewers only」コンテンツの権限は「Portal Content Reviewer」のみに指定する

準備ができたら、ページ上にAsset Publisherを置き、表示内容を「Webコンテンツ」に指定し、上記「WorktimeRoleContributor」モジュールがデプロイされてない状態で、「worktime_reviewer」としてログインしてみましょう。問題なければ、「visible to Users」と「visible to Reviewers only」両方が表示されています。

その後、「WorktimeRoleContributor」モジュールがデプロイされる状態で、システム時間を「月曜日〜金曜日の09:00 ~ 18:00」のうちに設定し、「worktime_reviewer」としてログインしてみましょう。問題なければ、Asset Publisherの表示は上記内容と一致しています。

そしてシステム時間を「月曜日〜金曜日の09:00 ~ 18:00」以外のものに設定し、「worktime_reviewer」としてログインしたら、「visible to Users」のみが表示されることを確認できます。

 

結論

RoleContributorはPermissionCheckerがDBからユーザのロールを取得したあとで、動的にユーザのロールをカスタマイズすることができます。

  •  ユーザ毎に割り当てられるロールだけではなく、組織などから継承されるロールも対象
  • PermissionCheckerのDBからロール取得をバイパスするロール(例:Administrator)は対象外
  • Liferayはスレッド(≈リクエスト)毎にPermissionCheckerを作成するのため、RoleContributorもリクエストごとに呼ばられる。そのため、RoleContributor中の時間を消費する操作(≈DBアクセス)をキャッシュなどにより最小限に抑えないといけない

RANKING
2021.01.08
2020.12.01
2020.10.30
2020.12.28
2020.12.18