CakePHP2 でログインページをたくさん作る方法を考えました!

◆2012年10月17日、追記。◆

CakePHP2 でログインページをたくさん作る方法再び♪ | oki2a24 にてまったく違う考え方でログインページをたくさん作る方法をメモしました。

この投稿が参考になった!!!とコメントを残してくだすった方がいらっしゃいましたので、ほかにもお求めの方がいらっしゃいましたら併せて閲覧いただき、何かの参考になればうれしく存じます。

・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・

ウェブサービスを作っていると、たとえば先生用のログインページはログインフォームだけでよいけれど、生徒用のログインページでは「新規登録はこちら!」のリンクも付けたい、、、ということがあると思います

ただし、ログイン処理はすべて同じとしたいのです。

しばらく悩んだのですが、prefix ルーティングで実現できそうです。

ポイント

  • appConfig/core.php の Routing.prefixes を修正して設定します。
    例:array(‘admins’, ‘editors’, ‘authors’)
  • コントローラーのアクション名で prefix ルーティングを使用することを知らせます。
    書き方は、ルーティング名 + アンダースコア + アクション名
    例:admins_login、editors_login、authors_login
  • ビューは、prefix ルーティング用に作成したアクションに対応するように作成します。
    例:admins_login.ctp、editors_login.ctp、authors_login.ctp

前提

環境の情報です。

  • 使用している CakePHP のバージョンは、2.2.0 です。
  • Windows 7、XAMPP 上で確認しています。

実践サンプル

CakePHP2 認証、Auth コンポーネントのサンプルを世界一シンプルを目指して作ります。 | oki2a24 のソースをいじってサンプルを作っていきます。

今回は、管理者(admins)、編集者(editors)、作者(authors)それぞれのログインページを作ろうと思います。あと、前の投稿で作成した、ただのログインページも残しておきます。

それぞれのログイン URL は次のようになります。

  • 管理者(admins) http://localhost/cakesample3/admins/users/login
  • 編集者(editors) http://localhost/cakesample3/editors/users/login
  • 作者(authors) http://localhost/cakesample3/authors/users/login

 新規・修正ソース一覧

  • app/Config/core.php
  • app/Controller/UsersController.php
  • app/View/Users/admins_login.ctp
  • app/View/Users/authors_login.ctp
  • app/View/Users/editors_login.ctp
  • app/View/Elements/all_links.ctp

具体的な修正内容

app/Config/core.php

Configure::write('Routing.prefixes', array('admins', 'editors', 'authors'));

ここを修正することで、管理者(admins)、編集者(editors)、作者(authors)の prefix ルーティングを使うように設定します。

app/Controller/UsersController.php

<?php
App::uses('AppController', 'Controller');
/**
 * Users Controller
 *
 * @property User $User
 */
class UsersController extends AppController {

/**
 * Called before the controller action.  You can use this method to configure and customize components
 * or perform logic that needs to happen before each controller action.
 *
 * @return void
 */
	public function beforeFilter() {
		// ログインなしでアクセス可能なページ(このコントローラーのアクション)を列挙
		$this->Auth->allow('logout');
	}

/**
 * ログイン処理
 */
	public function login() {
		$this->_login();
	}

/**
 * 管理者ログイン処理
 */
	public function admins_login() {
		$this->_login();
	}

/**
 * 編集者用ログイン処理
 */
	public function editors_login() {
		$this->_login();
	}

/**
 * 著者用ログイン処理
 */
	public function authors_login() {
		$this->_login();
	}

/**
 * ログアウト処理
 */
	public function logout() {
		$this->redirect($this->Auth->logout());
	}

/**
 * ログイン処理
 */
	private function _login() {
		// フォームに入力があった場合のみログイン処理を行い、ダッシュボードへ移動
		if ($this->request->is('post')) {
			$this->log($this->Auth, 'debug');
			if ($this->Auth->login()) {
				/* $this->redirect(array('controller' => 'apples', 'action' => 'index'));
				 * などと設定した場合は、prefix ルーティングを保ったままのリダイレクトが可能。
				 * 例:http://example.com/admin/users/login → http://example.com/admin/apples/
				 * 今回は認証後にprefix ルーティングを破棄したいため、引数には URL を直に指定する。
				 */
				$this->redirect('/apples/index');
			} else {
				$this->Session->setFlash(__('ユーザ名またはパスワードが誤っています。再度入力してください。'));
			}
		}
	}

}

ポイントに書いたとおりです。コントローラーに、ルーティング名 + アンダースコア + アクション名、と書くことでそれらのアクションにアクセスすると URL が /ルーティング名/コントローラ名/アクション名、に変化します。

あとは、ログイン処理はそれぞれのアクションでまったく同一なので内部の関数としてまとめました。

app/View/Users/admins_login.ctp
app/View/Users/authors_login.ctp
app/View/Users/editors_login.ctp

<h2>admins login ビュー</h2>
<div class="users form">
	<?php echo $this->Session->flash('auth'); ?>
	<?php echo $this->Form->create('User');?>
	<fieldset>
		<legend>
			<?php echo __('ユーザ名とパスワードを入力してください。'); ?>
		</legend>
		<?php
		echo $this->Form->input('username');
		echo $this->Form->input('password');
		?>
	</fieldset>
	<?php echo $this->Form->end(__('ログイン'));?>
</div>
<?php echo $this->element('all_links'); ?>

こちらはファイル名が重要なので app/View/Users/admins_login.ctp のみ掲載します。それぞれのファイルの違いは、h2 タグの内容だけです。

app/View/Elements/all_links.ctp

<div class="actions">
	<h3>リンク</h3>
	<ul>
		<?php
		/* echo "<li>" . $this->Html->link('adminsログイン', array('controller' => 'users', 'action' => 'admins_login')) . "</li>";
		 * のような、第2引数が array('controller' => 'users', 'action' => 'admins_login') の形式の場合、
		 * prefix ルーティングが有効となるので prefix に対応したアクション、ビューを作成する必要がある。
		 * 今回、prefix ルーティングは使用するが、対応したアクション、ビューは作成しないため、下記2つの対応を $this->Html->link に行う。
		 * ログインページ、つまり prefix ルーティングを設定しているアクションへのリンクは URL を直に記述する。controller と action を指定する方式だと prefix 後の URL とならないため。
		 * ログイン以外のページには、 prefix を無効にする設定を記述する。
		 */
		echo "<li>" . $this->Html->link('ログイン', '/users/login') . "</li>";
		echo "<li>" . $this->Html->link('adminsログイン', '/admins/users/login') . "</li>";
		echo "<li>" . $this->Html->link('editorsログイン', '/editors/users/login') . "</li>";
		echo "<li>" . $this->Html->link('authorsログイン', '/authors/users/login') . "</li>";
		echo "<li>" . $this->Html->link('ログアウト', array('admins' => false, 'editors' => false, 'authors' => false, 'controller' => 'users', 'action' => 'logout')) . "</li>";
		echo "<li>" . $this->Html->link('Apples', array('admins' => false, 'editors' => false, 'authors' => false, 'controller' => 'apples', 'action' => 'index')) . "</li>";
		echo "<li>" . $this->Html->link('Beets', array('admins' => false, 'editors' => false, 'authors' => false, 'controller' => 'beets', 'action' => 'index')) . "</li>";
		echo "<li>" . $this->Html->link('Cherries', array('admins' => false, 'editors' => false, 'authors' => false, 'controller' => 'cherries', 'action' => 'index')) . "</li>";

		?>
	</ul>
</div>

ポイントはソースのコメントに書いたとおりなのですが、もう一度書いておきます。

echo “<li>” . $this->Html->link(‘adminsログイン’, array(‘controller’ => ‘users’, ‘action’ => ‘admins_login’)) . “</li>”; のように、第2引数が array(‘controller’ => ‘users’, ‘admins_login’ => ‘login’) の形式の場合、prefix ルーティングが有効となります

すると /admins/users/login 後に別のページに移動したときも prefix ルーティングのページ、たとえば /admins/apples など、にアクセスしようとします。当然、それらのページはありませんので、アクセスできません。

今回、prefix ルーティングは使用するけれども、ルーティングに対応するログイン以外のアクション、ビューは作成しません。そこで、下記2つの対応を $this->Html->link のパラメータに対して行いました。

  1. ログインページ、つまり prefix ルーティングを設定しているアクションへのリンクは URL を直に記述しました。controller と action を指定する方式だと、その後にジャンプしたページの URL に prefix ルーティングを施してしまうからです。
  2. ログイン以外のページには、 prefix を無効にする設定を記述しました。第2引数の「’admins’ => false, ‘editors’ => false, ‘authors’ => false, 」部分です。

prefix ルーティングもまた、奥が深いですね♪

おわりに

実は今回の解決策にたどり着くまでにかなり悩みました。Auth コンポーネントをなんとか2つに分けて独立した認証にすればできるかもとか、でもそれだと ACL をやりたくなったときに面倒くさそうとか。。。

次のページは、携帯3キャリアで表示するページをちょっとだけ変える手法を紹介しているのですけれども、これだ!これを応用すればっ!とひらめきました。大変参考になりました、ありがとうございます。

また、本家ドキュメントにて、prefix ルーティングをオフにする使用方法がわかりました。当たり前ですけれども、本家ドキュメントはとても勉強になります。英語でも、時間をかけて、ゆっくり、確実に読んでおいたほうがより CakePHP を使いこなせる、そう感じました。

以上です♪

ディスカッションに参加

3件のコメント

  1. この方法が知りたかったです!ありがとうございます!

コメントを残す

コメントを残す