[CakePHP] シンプルな認証を実装する(認証の前半)

認証(ログインとログアウト)
http://book.cakephp.org/2.0/ja/tutorials-and-examples/blog-auth-example/auth.html#id3

のところを追加していく。チュートリアルではいきなり、AppController を書き換えてしまっているが、一度ログイン認証を実装してから、beforeFilter あたりを追加したほうが分かりやすいかも。実は「ログインした状態」を判別するのと、「ログインしたユーザーが操作ができるか」というのを判別するのとは別のことになる。例えば、ログインユーザーの名称をページに表示するために「ログインしているかどうか」の状態は必要かもしれないが、「ログインしたユーザーが操作できるか」は必要ない。操作が可能かどうかの判別は必要なのは、操作を拒否するときに限られるので。

公開するアクションの作成
http://book.cakephp.org/2.0/ja/core-libraries/components/authentication.html#id20

を見ると、全体が拒否(deny)の状態から、徐々に許可(allow)していくパターンになる。本来は、このほうが良いのだが、一部分だけ管理したい(denyしたい)場合がある。この場合は、$this->Auth->allow(); ですべてを許可してから、部分的に $this->Auth->deny(…); していくのだと思う。

[CakePHP] シンプルな認証を実装する(準備) – Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/4837

の続きとして、フォーム認証から実装しよう。

チュートリアルの通りに、User に対して認証を使ってみる。

■User にログイン/ログアウトを実装する

app/Controller/AppController.php に $components を追加する。

class AppController extends Controller {

    public $components = array(
        'Session',
        'Auth' );
}

こうすることで、$this->Session と $this->Auth が使えるようになる。

app/Controller/UsersController.php に、login と logout を追加する。

class UsersController extends AppController {
/**
 * ログイン
 */
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'));
        }
    }
}

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

app/View/Users/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>

app/Model/User.php で、保存時にパスワードをハッシュ化する。

App::uses('AppModel', 'Model');
App::uses('AuthComponent', 'Controller/Component');	// コンポーネントを追加
/**
 * User Model
 *
 */
class User extends AppModel {
/**
 * 保存時にパスワードをハッシュ化する
 */
	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;
	}
}

$this->Auth->login() では、ユーザー名とパスワードをチェックするのだが、パスワードはハッシュ値を使っている。なので、Model/User でパスワードを保存するときにハッシュ化しておく。これ、もともとのテーブルがハッシュ化してあればそれがいいんだけど、直書きの場合とか別な暗号化を行っている場合はどうなるんだろうか?ってのを調査しないと。

多分、

カスタム認証オブジェクトの作成
http://book.cakephp.org/2.0/ja/core-libraries/components/authentication.html#id5

あたりを使えばいけると思うのだが。

■試しに実行してみる

これを実行してみて http://localohst:81/cakeu/users/ にアクセスしてユーザーの一覧を表示させようとすると。

な風に、/users/login に飛ばされる。これは正しい操作で、Auth をインストールした時点で、ログインしていないユーザーは全ページのアクセスを禁止されているので、こうなる。デフォルトの設定として、ログインできていない場合は、/users/login に飛ばされるようになっているので、こんな動きになります。

で、通常の場合は、

  • ログインしていない状態でも Post の一覧(index)が見たい。
  • ログインしていない状態でも User の Add ができたい。
  • ログインしたら、なんらかのページにジャンプする。
  • ログアウトしたら、なんらかのページにジャンプする。

というのが必要な訳で、これを CakePHP のチュートリアルのように書き換えます。

■ログインしていない状態の設定

/Controller/AppController.php の beforeFilter を書き換えます。

class AppController extends Controller {

    public $components = array(
        'Session',
        'Auth' => array(
        	// ログイン後に /Posts/index へジャンプ
        	'loginRedirect' => array('controller' => 'posts', 'action' => 'index'),
        	// ログアウト後に /Pages/home へジャンプ
			'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home'))
		);

    public function beforeFilter() {
    	// 各コントローラーの index と view を有効にする
        $this->Auth->allow('index', 'view');
    }
}

Auth->allow メソッドは、公開するメソッドを羅列するので、この場合は「全コントローラーに対して index と view が有効になる」という設定になります。なので、Model ごとに細かい設定をすることも必要になり、User の add メソッドだけ有効(ユーザーを追加する)にするためには、/Controller/UsersController.php に beforeFilter を追加する必要があります。

/Controller/UsersController.php の beforeFilter を追加する。

class UsersController extends AppController {

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

これで、ログインしていないユーザーは、

  • /Users/
  • /Users/view
  • /Users/add
  • /Users/login
  • /Users/logout
  • /Posts/
  • /Posts/view

にアクセスできるようになります。login, logout はデフォルト値なので、これが変更になったときは別途設定が必要。

■改めてアクセスしてみる

今度は http://localohst:81/cakeu/users/ にアクセスしてユーザーの一覧が表示できます。

「List Posts」ボタンを押すと、/posts/ が表示できます。

編集しようと思って「Edit」ボタンを押すと、ログインの画面に強制的にジャンプします。

■ログインユーザーを作ってアクセスする

/Posts/edit などがアクセス禁止になっていることが分かったので、/users/add で、ログインユーザーを作ってアクセスしてみる。

Role は一般ユーザーということで「Users」としておきます。今回の users テーブルでは Role は自由に設定できるので、想定として「Administrators(管理者)」と「Users(制限ユーザー)」のようなイメージにしておけば ok かと。ブログの場合は「Author」とか「Editor」を使えばわかりやすい。

submit すると、/users/ へジャンプする。

この状態では、まだログインはしていないので、あらためて、/users/login にアクセスするか、アクセス禁止の Edit ボタンを押して、ログインの画面にジャンプ。

うまくログインができると、/pages/home にジャンプする。実はこのページはルートのページになるので、http://localhost:81/cakeu/ にアクセスした時と同じページがでる。

※実は、ここに落とし穴があって、ログインしていないユーザーが http://localhost:81/cakeu/ のようにルートにアクセスするとログイン画面に飛ばされる。SNS の場合にはそれでもいいんだけど、ブログのような場合は、ページ一覧 /posts/ に飛んで欲しかったりするよね。そんな場合は、Controller/AppController.php で Auth のところで authError を追加すればいいはずなんですが…うまくいきませんね。これは後で調査。

■ユーザー情報を使う

ログインしたことは確認できたので、ログイン情報を使って定番の「こんにちは○○さん」を出してみます。これはチュートリアルにないので、オリジナル的に…ってのは次で。

カテゴリー: CakePHP パーマリンク