Blog

concrete5の権限の実装を知る&ページ権限をPHPから変更する

Posted by admin at 21:08 日時 2014/01/01

※ concrete5では権限設定はすべてユーザーインターフェースからマウス操作で行なうことができますので、通常プログラミングは必要ありません。この記事はパッケージなどから自動で権限設定を変更したりしたい場合のための内容です。調べながら書いているので、間違ってたらすいません。

さて、concrete5は高度かつ柔軟な権限管理が可能なことが特長で、それは設計にも現れています。concrete5では、ページ、エリア、ブロック、ファイル、ファイルセット、ユーザー等々concrete5が扱う各オブジェクトに対してすべて個別に権限設定が可能です。当然それぞれのオブジェクトで権限の扱い方は異なります(例えば、「編集できるかどうか」という権限の意味は、エリアの場合は中にブロックを追加することができるかどうか、ブロックの場合はそのブロック自体を編集することができるかどうか、と変わります)が、公式ドキュメント「コンテンツの権限」にて解説されている様に、Permissionsクラスのコンストラクターに権限を確認したいオブジェクトを渡すことで、統一されたシンプルなAPIで権限をチェックすることができます。

// ページの権限をチェックする  $p = new Permissions($page);  $p->canRead();    // エリアの権限をチェックする  $area = Area::get($page, 'Main');  $p = new Permissions($area);  $p->canRead();

Permission クラスのコンストラクタで何が行なわれているかというと、渡されたオブジェクトを解析して、オブジェクトに対応した PermissionResponse クラスのオブジェクトを取得しています。ページの場合は PagePermissionResponse クラスで、オブジェクトごとに AreaPermissionResponse、FilePermissionResponse などが存在します。

それでは、Permissionクラスで canRead メソッドを呼び出した際の処理はどのようになっているのでしょうか。PagePermissionResponse など、PermissionResnponse クラスの子クラスは、canRead や canWrite などの抽象的なメソッドからそれぞれのオブジェクトごとに対応した権限キーへのアクセスをする橋渡しの役割になります。例えば、ページの場合 canRead メソッドがコールされると PagePermissionResponse クラスが “view_page” という権限キーを検証します。

権限キーの検証は、PermissionKey クラスの子クラスで行なわれ、ページの場合は PagePermissionKey クラスになります。ただし、権限キーのオブジェクト自体はデータベースとやりとりせず、データベースへのアクセスを担当するのは PermissonAccess クラスが担当します。ページの場合は PagePermissionAccess クラスです。

PagePermissonAccess クラスは、データベースを検索し、PermissonAccessEntity と PermissionDuration クラスを使って、調べようとしている権限キーに対応するアクセスエンティティと権限の期間設定を探し出し、ログイン中のユーザーが条件を満たしているかどうかを判定します。アクセスエンティティとは、権限設定の単位の総称で、ユーザー、グループ、グループセット、ページの所有者などが該当します。権限の期間設定は権限ごとにできるものとできないものがありますが、PermissionAccess クラスの子クラスごとの実装の違いによって、その差異を吸収するようになっています。

全体の流れを示したのが以下の図です。

このように、concrete5の権限の実装は複雑に抽象化されているため、開発者は Permission クラスを通して、非常にシンプルなAPIで、それがページなのか、エリアなのか、ファイルなのか、そう言ったオブジェクトごとの差異を気にせずにかんたんに権限のチェックを行なうことができます。

その反面、権限設定の追加や削除をプログラムから行なう際は上記のモデルごとの関係性を理解していないと非常に分かりにくいです。ここでは、ページの権限をプログラムから取り扱う例についてご紹介しますが、オブジェクトごとに取り扱いは異なるので注意してください。

まず、ページに特有の権限周りの初期設定は、Pageオブジェクトから行なえるようになっています。

// ページオブジェクトの取得  $c = Page::getByID($cID, "RECENT");    // 「権限を割り当てる:サイトエリア(階層順)」に変更  $c->inheritPermissionsFromParent();  // 「権限を割り当てる:ページタイプのデフォルトから」に変更  $c->inheritPermissionsFromDefaults();  // 「権限を割り当てる:手動で」に変更  $c->setPermissionsToManualOverride();    // 「サブページ権限:ページタイプのデフォルトの権限設定を継承する」に変更  $c->setPermissionsInheritanceToTemplate();  // 「サブページ権限:このページの権限を継承する」に変更  $c->setPermissionsInheritanceToOverride();    // 権限を継承しているページのオブジェクトを取得  $pc = $c->getPermissionsCollectionObject();    // 権限設定を全消去  $c->clearPagePermissions();

権限設定を個別に変更したい場合は、まず権限キーオブジェクトを取得します。

// ページの「表示」権限キーオブジェクトを取得  $pk = PagePermissionKey::getByHandle('view_page');

次に、権限を確認・変更したいオブジェクトをセットします。

$pk->setPermissionObject($c);

そして、データベースとのやり取りのために PermissonAccess オブジェクトを取得します。

$pa = $pk->getPermissionAccessObject();  if (!is_object($pa)) {  	$pa = PermissionAccess::create($pk);  } else if ($pa->isPermissionAccessInUse()) {  	$pa = $pa->duplicate();  }

ここで注意したいのは、既存の PermissionAccess レコードを取得した場合、それを直接変更してしまうと、サイトの他のページにも影響を与える可能性がありますので、設定変更したいページのために複製して新しい PermissionAccessID を取得してから使います。

下準備が終わったので、次に権限を設定したいAccessEntityオブジェクトを取得します。

$g = Group::getByID(GUEST_GROUP_ID);  $pe = GroupPermissionAccessEntity::getOrCreate($g);

次に、PermissionAccess オブジェクトに指定した AccessEntity オブジェクトの追加を指示して、データベースに設定変更を保存することができます。

$pa->addListItem($pe, false, PagePermissionKey::ACCESS_TYPE_INCLUDE);

addListItem() の第2引数に PermissionDuration オブジェクトを指定して権限設定の有効期間を指定することもできます。第3引数は PagePermissionKey::ACCESS_TYPE_EXCLUDE に変更することで「除外」設定を追加することができます。

設定の削除は removeListItem() を使います。

$pa->removeListItem($pe);

addListItem() または removeListItem() が終わったら、最後に PermissionAssignment オブジェクトに PermissionAccess オブジェクトをアサインして処理終わりです。この処理がなぜ必要なのかイマイチ分かってないですが…

$pt = $pk->getPermissionAssignmentObject();  $pt->assignPermissionAccess($pa);

Permissionクラスではログイン中のユーザーに対するチェックになりますが、特定のグループに対してチェックするということもできます。

$pk = PagePermissionKey::getByHandle('view_page');  if(is_object($pk)){  	$g = Group::getByID(GUEST_GROUP_ID);  	$pe = GroupPermissionAccessEntity::getOrCreate($g);  	$pk->setPermissionObject($c);  	$pa = $pk->getPermissionAccessObject();  	if ( $pa->validateAccessEntities(array($pe)) ) {  		// ゲストが該当のページを見ることができる  	} else {  		// ゲストが該当のページを見ることができない  	}  }

参考記事:Programmatically setting advanced permissions


Share this entry