CakePHP2 でログインページをたくさん作る方法再び♪

以前、CakePHP2 でログインページをたくさん作る方法を考えました! | oki2a24 では prefix ルーティングを使用してたくさんのログインページを、同じログイン処理で作る方法をメモしました。

今思うと、prefix ルーティングを使わなくても、たくさんのログインページを作ることは可能でした。今回、その方法をメモします。

ポイント

  • ユーザ名、パスワードを入れるフォームを持ったビュー、それを受け取りログイン処理を行うコントローラーを複数作ればよいです。
  • 各ログイン処理のコントローラーでログイン後にジャンプするアクションを指定します。$components の Auth の loginRedirect で指定しますが、redirect 関数でもよいでしょう。

実際にやってみた

下地となるモデル、コントローラー、ビューの用意

CakePHP2 調べ物するときのスキーマメモ(個人的) | oki2a24 でデータベースにテーブルをつくり、bake all でそれぞれのモデル、コントローラー、ビューを作成します。

ログイン処理の作成

認証処理のベースとしているのは CakePHP2 本家ドキュメントの次のページです。

実際に、次のようにコーディングしました。

app/Controller/AppController.php

class AppController extends Controller {
	public $components = array(
			'Auth' => array(
					'loginAction' => '/',
			),
			'DebugKit.Toolbar',
			'Session'
	);
}

ログイン認証前の場合はログインページなどに飛ばしてあげる必要があります。それが、loginAction ですが、複数のログインページがあるためどこかのログインページに飛ばすことはしないで、今回はCakePHP インストールできたか確認するのにアクセスするルートページとしました。

app/Controller/GroupsController.php

	public function beforeFilter() {
		parent::beforeFilter();
		$this->Auth->allow('add'); // ユーザーに自身で登録させる
	}

ログイン認証しなくても、グループが登録できるようにしています。

app/Controller/UsersController.php

	public function beforeFilter() {
		parent::beforeFilter();
		$this->Auth->allow('add'); // ユーザーに自身で登録させる
	}

	public function logout() {
		$this->redirect($this->Auth->logout());
	}

先ほど app/Controller/AppController.php で全コントローラーに対して認証コンポーネントを有効にしたため、ユーザの登録ができません。そこで、 beforeFilter 関数でユーザー登録は認証なしで行えるようにしました。

また、ログインページは複数用意しましたが、ログアウト処理はひとつでもよいと考えたため、このコントローラーにログアウト処理である logout アクションを作成しました。

$this->Auth->logout() の返却値は logoutRedirect ですが、特に設定しなければ loginAction となり、今回はこちらです。

app/Model/User.php

	public function beforeSave($options = array()) {
		if (isset($this->data[$this->alias]['password'])) {
			$this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
		}
		return true;
	}

User モデル、つまり対応する users テーブルに INSERT や UPDATE の SQL を発行する前にパスワードを暗号化する処理を入れています。

複数のログインページ

今回、グループを3つ考え、それに対応してログインページを3つ作ることにしました。グループはなんでもよいのですが、次のようにしました。

  • ブッダ
  • ニンジャ
  • サラリマン

そこで、ログイン URL もそれにあわせて、

  • http://localhost/cake07/buddhas/login
  • http://localhost/cake07/ninjas/login
  • http://localhost/cake07/salarymen/login

とします。このため、次のコントローラー、ビューを新たに作成します。

  • ブッダ → app/Controller/BuddhasController.php app/View/Buddhas/login.ctp
  • ニンジャ → app/Controller/NinjasController.php app/View/Ninjas/login.ctp
  • サラリマン → app/Controller/SalarymenController.php app/View/Salarymen/login.ctp

app/Controller/BuddhasController.php

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

	public $components = array(
			'Auth' => array(
					'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
			),
	);

	public $uses = array('User');

	public function beforeFilter() {
		parent::beforeFilter();
		$this->Auth->allow();
	}

	public function login() {
		if ($this->request->is('post')) {
			if ($this->Auth->login()) {
				$this->redirect($this->Auth->redirect());
			} else {
				$this->Session->setFlash(__('Invalid username or password, try again'));
			}
		}
	}
}

ポイントは、loginRedirect で、ログイン成功後にジャンプする先を設定していることです。ほか2つのログインアクションでも設定しており、ジャンプ先はもちろん別にしています。

app/View/Buddhas/login.ctp

<div class="users form">
	<?php echo $this->Session->flash('auth'); ?>
	<?php echo $this->Form->create('User'); ?>
	<fieldset>
		<legend>
			<?php echo __('Please enter your username and password'); ?>
		</legend>
		<?php
		echo $this->Form->input('username');
		echo $this->Form->input('password');
		?>
	</fieldset>
	<?php echo $this->Form->end(__('Login')); ?>
</div>

コードの中で Login ボタンを押したときに実行するコントローラーのアクションを指定しなくても、自動的に BuddhasController の login アクションが呼ばれる、というのがポイントといえばポイントかもしれません。

残りのニンジャ、サラリマンのグループも以上と同じ構造です。コードだけ掲載します。

app/Controller/NinjasController.php

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

	public $components = array(
			'Auth' => array(
					'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
			),
	);

	public $uses = array('User');

	public function beforeFilter() {
		parent::beforeFilter();
		$this->Auth->allow();
	}

	public function login() {
		if ($this->request->is('post')) {
			if ($this->Auth->login()) {
				$this->redirect($this->Auth->redirect());
			} else {
				$this->Session->setFlash(__('Invalid username or password, try again'));
			}
		}
	}
}

app/View/Ninjas/login.ctp

このコードは app/View/Buddhas/login.ctp とまったく同じため省略します。

app/Controller/SalarymenController.php

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

	public $components = array(
			'Auth' => array(
					'loginRedirect' => array('controller' => 'widgets', 'action' => 'index'),
			),
	);

	public $uses = array('User');

	public function beforeFilter() {
		parent::beforeFilter();
		$this->Auth->allow();
	}

	public function login() {
		if ($this->request->is('post')) {
			if ($this->Auth->login()) {
				$this->redirect($this->Auth->redirect());
			} else {
				$this->Session->setFlash(__('Invalid username or password, try again'));
			}
		}
	}
}

app/View/Salarymen/login.ctp

このコードも app/View/Buddhas/login.ctp とまったく同じため省略します。

動かしてみます

http://localhost/cake07/groups/add と http://localhost/cake07/users/add にアクセスして、ブッダ、ニンジャ、サラリマンのグループを登録し、それぞれのグループのユーザを登録します。

それぞれのログインページに行き、ログインしてみてジャンプ先が設定通りになっていれば、成功です!

おわりに

同じコードが結構あります。同じことを何度も書くのは非常によろしくありませんのでまとめるなどの対策を行う必要があります。課題ですね。

ですがひとまず完成しました。次の目標は、それぞれのグループにパーミッションを割り当てて、ページへのアクセス権限を設定してあげることになるでしょうか。検討してみたいと思っています♪

コメントを残す

コメントを残す