Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

さくらvpsとcakephp2.6.7で開発日記 その0005 ログインフォームを作成してセッション情報はデータベースに保存する

参考にさせて頂いたページ

Authコンポーネントについて

認証 — CakePHP Cookbook 2.x ドキュメント

【CakePHP】Authコンポーネント - Qiita

シンプルな認証と承認のアプリケーション実装例について

シンプルな認証と承認のアプリケーション — CakePHP Cookbook 2.x ドキュメント

CakePHP で Session の保存先にデータベースを使用する方法について

CakePHP で Session の保存先にデータベースを使用する方法 | ウェブル

cakephpのセッションについて

セッション — CakePHP Cookbook 2.x ドキュメント

セッション保存用のテーブルを作成する

実行したsqlセッション — CakePHP Cookbook 2.x ドキュメントにならって以下の通り。

CREATE TABLE `cake_sessions` (
  `id` varchar(255) NOT NULL DEFAULT '',
  `data` text,
  `expires` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

Config/core.phpの編集

core.phpを見ると

 Configure::write('Session', array(
        'defaults' => 'php'
    ));

上記のように、初期設定がphpになっているので、

Configure::write('Session',array(
    'defaults' => 'database', // Session情報をデータベースに保存する
    'cookie' => 'SID', // cookieの配列のキー名この場合$_COOKIE['SID']
    'timeout' => 2160, // CakePHP のセッションハンドラがセッションを破棄するまでの時間で単位は分(36時間)
    // php.iniの設定内容を上書き
    'ini' => Array(
        'session.cookie_secure' => false, // httpとhttpsが混在しているサービスではfalse
        'session.cookie_lifetime' => 129600, // ブラウザに送信するクッキーの有効期間で単位は秒(36時間)
        'session.gc_maxlifetime' => 129600, // データが 'ごみ' とみなされ、消去されるまでの秒数(36時間)
        'session.gc_divisor' => 100 // デフォルトは100 
    )
));

とした。

Controller/AppController.phpを編集する

$componentsにAuthを渡したり、beforeFilterの処理内容を追加して、記述内容は以下の通り。

<?php
/**
 * Application level Controller
 *
 * This file is application-wide controller file. You can put all
 * application-wide controller-related methods here.
 *
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
 * @link          http://cakephp.org CakePHP(tm) Project
 * @package       app.Controller
 * @since         CakePHP(tm) v 0.2.9
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 */

App::uses('Controller', 'Controller');

/**
 * Application Controller
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @package     app.Controller
 * @link        http://book.cakephp.org/2.0/en/controllers.html#the-app-controller
 */
class AppController extends Controller {
  public $components = array(
    'DebugKit.Toolbar',
    'Session',
    'Auth' => array(
      // 認証が必要な画面を直接指定されたときのリダイレクト先
      'loginAction' => array(
        'controller' => 'users',
        'action' => 'login',
        'admin'=>true
      ),
      // ユーザのログインに使いたい認証オブジェクトの配列設定
      'authenticate' => array(
        'Form' => array(
          'fields' => array(
            'username' => 'email', // emailフィールドの値で認証
            'password' => 'password' // passwordフィールドの値で認証
          ),
          'scope' => array(
            'is_registered' => 1 // is_registeredフィールドの値も認証条件に追加
          ),
          'passwordHasher' => 'Blowfish'
        )
      ),
      // ログイン直後に表示するページを指定
      'loginRedirect' => array('controller' => 'users', 'action' => 'login'),
      // ログアウト直後に表示するページを指定
      'logoutRedirect' => array('controller' => 'pages', 'action' => 'index'),
      // 未ログイン時のメッセージ
      'authError' => 'メールアドレスまたはパスワードが違います。'
    )
  );
  //どのアクションが呼ばれてもはじめに実行される処理
  public function beforeFilter() {
    // ログイン中のユーザー情報を取得
    $user = $this->Auth->user();
    $this->set('user',$user);
    // ログインしていないときでも許可されているアクション (allow()はすべてのアクションを許可)
    $this->Auth->allow();
  }
}

Controller/UsersController.phpを作成する

記述内容は以下の通り。

<?php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
  // Controller名
  public $name = 'Users';
  // 使用するModel
  public $uses = array('User');

  public function login() {
    // 送信データが無いとき、またはpostアクセス以外の処理
    if(!$this->request->data || !$this->request->is('post')){
      $this->render();
      return;
    }

    // 認証
    if(!$this->Auth->login()){
      // ログイン失敗時の処理
      $this->Session->setFlash('ユーザー名またはパスワードが違います。');
      return;
    }

    // 以下はログイン成功時の処理
    $this->Session->setFlash(__('ログイン成功'));

    // ログイン中のユーザー情報を取得
    $user = $this->Auth->user();
    $this->set('user',$user);
    $this->redirect($this->Auth->redirectUrl());
  }

  public function logout(){
    $this->autoRender = false;
    $logout_url = $this->Auth->logout();
    $this->redirect($logout_url);
  }
}

View/Users/login.ctp

記述内容は以下の通り。

<h1>ログイン</h1>

<br><br>
<?php
// ログイン判定
if(isset($user)){
  echo('<p>現在ログイン中のユーザー情報は以下の通りです。</p>');
  print_r($user);
}else{
  echo('現在ログインしていません。');
}
?>
<br><br>

<?php
echo($this->Form->create('User'));
?>
<div>
<?php
echo $this->Form->label('email', 'メールアドレス: ');
echo $this->Form->text(
  'email',
  array(
    'errorMessage' => false,
    'div' => false,
    'required' => false
  )
);
?>
</div>

<div>
<?php
echo $this->Form->label('password', 'パスワード: ');
echo $this->Form->password(
  'password',
  array(
    'errorMessage' => false,
    'div' => false,
    'required' => false
  )
);
?>
</div>

<?php
echo($this->Form->end('ログイン'));
?>

今回学習できたこと

全てのアクションの前に実行させたい処理について

以下のように、AppControllerにbeforeFilterを記述することで、実行できる。

  public function beforeFilter() {
    〜処理内容〜
  }

各Controllerに個別に処理を追加したい場合は、

public function beforeFilter() {
    parent::beforeFilter();
    〜当該のController〜で実行したい処理
}

のように記述する。

ログインしていないときに表示できるページを制限する

beforeFilter内で下記のように記述すると、ログインしていないときでも全てのアクションを許可する設定になる。

$this->Auth->allow();

beforeFilter内で下記のように記述すると、ログインしていないときに全てのアクションが許可されない設定になる。

$this->Auth->deny();

全てのアクションが許可されていない場合は下記のように$componentsに設定したアクションだけが表示される。

      // 認証が必要な画面を直接指定されたときのリダイレクト先(ログインページ)
      'loginAction' => array(
        'controller' => 'users',
        'action' => 'login'
      ),

だいたいはAppControllerのbeforeFilter内で$this->Auth->allow();を書いて、denyしたい箇所だけ各Controllerに書いたら良さそうな感じがする。