CakePHP(2.6.4)を使ったシンプルなユーザー登録のメモ。
※本記事には修正が必要な個所がありますした。(参考)
※なお、上記修正内容はすでに反映済みです
#概要
ユーザー登録画面にて「メールアドレス」と「パスワード」を入力し登録を行う。
なお、ユーザー名は「メールアドレス」を利用する。
#実装内容
##Userモデル(User.php)及びUserテーブル
Userモデルには独自検証ルールと保存前処理を実装。
ユーザー登録時のパスワードのハッシュ化はbeforeSaveにてBlowfishPasswordHasherを用いて行う。
重複ユーザーの登録が行われないよう重複チェック(isUnique)を実装。
重複ユーザーの登録が行われないよう標準ルールのisUniqueを利用。
また、パスワード欄とパスワード(確認)欄の一致を検証するため一致チェック(passwordConfirm)を実装。
パスワードに利用可能な文字を半角英数字(記号可)とする為のチェック(alphanumericsymbols)を実装。
検証ルールについては主に以下の内容を指定。
メールアドレスをキーとして重複登録のチェックを標準ルールの重複チェック(isUnique)を指定。
パスワード欄には半角英数字(記号可)のみ入力可能とする為、Userモデルに実装した文字種チェック(alphanumericsymbols)を指定。
同様にパスワード欄とパスワード(確認)欄を用いてパスワードの誤入力(勘違い)を防ぐ為、両フィールドの一致をチェックする為、一致チェック(passwordConfirm)を指定。
<?php
App::uses('BlowfishPasswordHasher', 'Controller/Component/Auth');
class User extends AppModel {
var $name = 'User';
var $useTable = 'users';
public $validate = array(
'email' => array(
array(
'rule' => 'notEmpty',
'message' => 'メールアドレスを入力してください'
),
array(
'rule' => 'email',
'message' => '正しいメールアドレスを入力してください'
),
array(
'rule' => 'isUnique',
'message' => '入力されたメールアドレスは既に登録されています'
),
),
'password' => array(
array(
'rule' => 'notEmpty',
'message' => 'パスワードを入力してください'
),
array(
'rule' => 'alphanumericsymbols',
'message' => 'パスワードに使用できない文字が入力されています'
),
array(
'rule' => array('minLength', 8),
'message' => 'パスワードは8文字以上入力してください',
),
array(
'rule' => 'passwordConfirm',
'message' => 'パスワードが一致していません'
),
),
'password_confirm' => array(
array(
'rule' => 'notEmpty',
'message' => 'パスワード(確認)を入力してください'
),
),
);
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$passwordHasher = new BlowfishPasswordHasher();
$this->data[$this->alias]['password'] = $passwordHasher->hash(
$this->data[$this->alias]['password']
);
}
return true;
}
public function passwordConfirm($check){
//2つのパスワードフィールドが一致する事を確認する
if($this->data['User']['password'] === $this->data['User']['password_confirm']){
return true;
}else{
return false;
}
}
public function alphanumericsymbols($check){
$value = array_values($check);
$value = $value[0];
return preg_match('/^[a-zA-Z0-9\s\x21-\x2f\x3a-\x40\x5b-\x60\x7b-\x7e]+$/', $value);
}
}
CREATE TABLE users (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255),
password VARCHAR(255),
created DATETIME DEFAULT NULL,
modified DATETIME DEFAULT NULL
) ENGINE = InnoDB;
##Signupコントローラー(SignupController.php)
Signupコントローラーではユーザー登録作業を実施。
indexアクションでは、入力データが送信されていない場合は「$this->render()」にてindexビュー(Signup/index.tpl)を表示し、入力データが存在する場合は「$this->User->invalidFields()」にて検査を実施。
検査を通った場合は入力内容を保存し、最後にサンクス画面を表示して終了。
なおセキュリティを高める為、Securityコンポーネントを利用。
不正なアクセスが行われた場合あらかじめ設定したblackholeメソッドの処理を実行。
(ここではエラーメッセージをセットし呼び出し元にリダイレクト)
<?php
class SignupController extends AppController {
public $name = 'Signup';
public $uses = array('User');
public $components = array(
'Security',
);
public function beforeFilter() {
parent::beforeFilter();
$this->Security->blackHoleCallback = 'blackhole';
}
public function index(){
if(!$this->request->data){
$this->render();
return;
}
//入力データをセット
$this->User->set($this->request->data);
//入力内容を検査
if($this->User->validates()){
//モデルの状態をリセット
$this->User->create();
//入力済みデータをモデルにセット
$user = array('User' => $this->request->data['User']);
//データを保存
$this->User->save($user);
//サンクス画面を表示
$this->render('thanks');
}
}
public function blackhole($type) {
$this->Session->setFlash('不正なリクエストが行われました');
$this->redirect(array('controller' => $this->controller, 'action' => $this->action));
}
}
##Usersコントローラー(UsersController.php)
Usersコントローラーでは、ログイン及びログアウト処理と認証を必要なページとしてmypageアクションを実装。
今回はユーザー名としてメールアドレスを利用する為、「fields」にて「'username' => 'email'」を指定する。
またハッシュ化にBlowfishPasswordHasherも利用している為、「passwordHasher」にて「Blowfish」を指定。
なお、loginアクション及びlogoutアクションは未認証状態でもアクセス可能とする必要がある為、あらかじめ「beforeFilter」にて除外を行う。
loginアクションにて認証情報が送信されてきた場合は、ログイン処理を実施する。
認証が通った場合は、あらかじめ設定されたURLにリダイレクトする。
logaoutアクションが呼ばれた場合、ログアウト処理を実施しログアウト完了画面を表示する。
こちらでもセキュリティを高める為、Securityコンポーネントを利用。
不正なアクセスが行われた場合あらかじめ設定したblackholeメソッドの処理を実行。
(ここではエラーメッセージをセットし呼び出し元にリダイレクト)
<?php
class UsersController extends AppController {
public $name = 'Users';
public $uses = array('User');
public $components = array(
'Auth' => array(
'authenticate' => array(
'Form' => array(
'passwordHasher' => 'Blowfish',
'fields' => array(
'username' => 'email',
'password' => 'password',
),
)
),
'loginAction' => '/users/login',
'loginRedirect' => '/users/mypage',
),
'Session',
'Security',
);
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('login', 'logout');
$this->Security->blackHoleCallback = 'blackhole';
}
public function login() {
//フォームから情報が送信された場合のみの認証を実施
if ($this->request->is('post')) {
//認証処理を実施
if($this->Auth->login()){
//認証に成功した場合は、設定されたURLへリダイレクト
return $this->redirect($this->Auth->redirectUrl());
}else{
$this->Session->setFlash('ログインに失敗しました');
}
}
}
public function logout() {
//ログアウトを実施
$this->Auth->logout();
//ログアウト完了画面を表示
$this->render('logout');
}
public function mypage() {
}
public function blackhole($type) {
$this->Session->setFlash('不正なリクエストが行われました');
$this->redirect(array('controller' => $this->controller, 'action' => $this->action));
}
}
#総括及び課題(疑問)
最もシンプルなユーザー登録の処理の為、アカウントの有効化やメールアドレスの検証等の処理は未実装。
パスワードのハッシュ化はSimplePasswordHasherにて行ったが、アルゴリズムの選択や強度の設定ができるはずなので確認が必要。
パスワードのハッシュ化はBlowfishPasswordHasherにて行ったが、強度の設定等についても確認が必要。
その他、例えばソーシャルログインも実装する場合も考慮するとテーブル構成は見直す必要があると思われる。
(メールアドレスが必ず入手可能ではない為)
#参考
#【参考】各種ビュー
<?php echo $this->Form->create(); ?>
<?php echo $this->Form->label('User.email', 'メールアドレス:'); ?>
<?php echo $this->Form->text('User.email'); ?>
<?php echo $this->Form->error('User.email'); ?>
<?php echo $this->Form->label('User.password', 'パスワード:'); ?>
<?php echo $this->Form->password('User.password'); ?>
<?php echo $this->Form->error('User.password'); ?>
<?php echo $this->Form->label('User.password_confirm', 'パスワード(確認):'); ?>
<?php echo $this->Form->password('User.password_confirm'); ?>
<?php echo $this->Form->error('User.password_confirm'); ?>
<?php echo $this->Form->end('登録'); ?>
登録しました
<?php echo $this->Form->create(); ?>
<?php echo $this->Form->label('User.email'); ?>
<?php echo $this->Form->text('User.email'); ?>
<?php echo $this->Form->label('User.password'); ?>
<?php echo $this->Form->password('User.password'); ?>
<?php echo $this->Form->end('ログイン'); ?>
<p>ログアウトしました</p>
<p><a href="/users/login/">ログイン</a></p>
<p>マイページ</p>
<p><a href="/users/logout/">ログアウト</a></p>