RoleContributorでユーザのロールを更新する - aegif Labo Blog Liferay
こんにちは。今回は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アクセス)をキャッシュなどにより最小限に抑えないといけない
