ACLアドオンを導入すると、モジュールやコントローラ単位でのアクセス制御が可能になります。アクセス制御の設定は
addon/acl/Config.php で行います。
インストール直後の設定を見てみましょう。
public function configure()
{
$index = $this->module("index");
$index->allow();
}
初期状態では indexモジュール が public となっています。allow()メソッド を引数無しでコールすると、そのモジュール(またはコントローラ)は public となります。allow()メソッド にはアクセスを許可するロールを指定します。
例えば下記は
manager ロールが与えられたユーザに indexモジュール へのアクセス権限を与えます。
public function configure()
{
$index = $this->module("index");
$index->allow("manager");
}
この状態でindexモジュールへリクエストすると
403 FORBIDDEN となります。
ロールの指定にはORやAND、括弧を用いることも可能です。
$index->allow("(foo|bar)&baz");
アクセス制限はコントローラごとに行うことも可能です。よくある例として「userモジュールはアクセス制御(ログインしているユーザのみ)を行うが、login と register コントローラだけは public とする」の設定例を下記に示します。
$user = $this->module("user");
$user->allow("user");
$user->controller("login")->allow();
$user->controller("register")->allow();
controllers()メソッド を使用して複数のコントローラの一括設定も可能です。
$user = $this->module("user");
$user->allow("user");
$user->controllers("login", "register")->allow();
ロールを与えるには ACLユーザオブジェクト の addRole()メソッド をコールします。コントローラ(アクション)内からは、
$this->aclUser でアクセスできます。
public function myAction()
{
$this->aclUser->addRole("user");
}
また login()メソッド を使用することもできます。第1引数はログイン後のリダイレクト先を指定します。通常はマイページのような場所に遷移させるでしょう。
public function loginAction()
{
$this->aclUser->login("n: user, c: main, a: top", "user");
}
ACLユーザオブジェクトは内部でセッションを使用していますので、リクエストをまたぐ継続されたデータを扱うことができます。
$this->aclUser->id = $aUser->id;
$aUser = new User($this->aclUser->id);
スコープ
サービスには一般ユーザと管理者ユーザが存在することがあります。そのようなサービスでは userモジュール と manageモジュール を作成することがあります。
config/Map.php
class Config_Map extends Sabel_Map_Configurator
{
public function configure()
{
$this->route("user")
->uri("user/:controller/:action")
->module("user")
->defaults(array(
":controller" => "index",
":action" => "index"
));
$this->route("manage")
->uri("manage/:controller/:action")
->module("manage")
->defaults(array(
":controller" => "index",
":action" => "index"
));
...
}
}
この時、ACLの設定は下記のようになります。
addon/acl/Config.php
class Acl_Config implements Sabel_Config
{
...
public function configure()
{
...
$user = $this->module("user");
$user->allow("user");
$manage = $this->module("manage");
$manage->allow("manager");
}
...
}
複数のモジュールが存在するとき、データのキーが重複する可能性が高くなります。
例えば、管理者ログイン後、管理者IDをACLユーザオブジェクト(セッション)に格納します。
$this->aclUser->addRole("manager");
$this->aclUser->id = $aManager->id;
管理者はサービスを覗くために、別のタブなどで一般ユーザとしてログインするかもしれません。この時、下記のように
idキー にユーザIDを格納するようにコーディングしていると管理者IDが上書きされてしまい、管理者はログアウトされた状態となってしまいます。
$this->aclUser->addRole("user");
$this->aclUser->id = $aUser->id;
この問題を回避するためにスコープという概念(機能)があります。スコープを指定するには下記のように設定します。
$user = $this->module("user");
$user->scope("user");
$user->allow("user");
$manage = $this->module("manage");
$manage->scope("manager");
$manage->allow("manager");
上記の例では userモジュール へのリクエスト時はスコープを "user" に、manageモジュール へのリクエスト時はスコープを "manager" に設定しています。スコープを設定することで、同じ
idキー でも他の場所に格納されることとなります。
class User_Controllers_MyController extends Sabel_Controller_Page
{
public function myAction()
{
...
$this->aclUser->id = $aUser->id; // data[user][id] = $aUser->id
}
}
class Manager_Controllers_MyController extends Sabel_Controller_Page
{
public function myAction()
{
...
$this->aclUser->id = $aManager->id; // data[manager][id] = $aManager->id
}
}
set()メソッド の第3引数や get()メソッド の第2引数で指定したスコープのデータにアクセスすることも可能です。
public function myAction()
{
// data[user][key] = "value"
$this->aclUser->set("key", "value", "user");
// data[manager][key]
$this->aclUser->get("key", "manager");
}
ACL設定でスコープを指定していない場合は
Acl_User::DEFAULT_SCOPE に格納されます。下記は明示的にそのデフォルトスコープにset, getするコーディング例です。
public function myAction()
{
$this->aclUser->set("key", "value", Acl_User::DEFAULT_SCOPE);
$this->aclUser->get("key", Acl_User::DEFAULT_SCOPE);
}
ログインページへのリダイレクトとログイン後のリダイレクト先
アクセス許可がされていない(ロールが与えられてない)時は通常
403 FORBIDDEN となるだけですが、ログインページへリダイレクトすることもACL設定で可能です。例えば userモジュール は "user" ロールが必要で、ログインページの内部URIが "n: default, c: login, a: form" の時、下記のような設定となります。未ログイン状態で userモジュール にアクセスするとログインページへリダイレクトされます。
$user = $this->module("user");
$user->allow("user");
$user->authUri("n: default, c: login, a: form");
ログインアクションは通常と同様、下記のようになります。
ただし、authUriメソッドによってログインページが設定されている場合はこのログイン後リダイレクト先(第1引数)ではなく、ログイン前にアクセスしたページへ遷移されます。
public function loginAction()
{
$this->aclUser->login("n: user, c: main, a: top", "user");
}
なお、ログイン前のアクセスがPOSTによるリクエストであったり、ログインページへリダイレクト後、他のページに1度でも移動した場合はログイン前にアクセスしたページへ戻ることはありません。
ログウアウト処理
ログアウトをするにはdeAuthenticate()メソッドを使用します。
public function logoutAction()
{
$this->aclUser->deAuthenticate();
}