m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

cakephp3でのauth認証

ちょっといじってあります

サンプルソースの通りにやってもうまく動かなかったのでいくつか修正しています

前提

  • usersテーブルを使用
  • SimplePasswordHasher使用

準備

usersテーブルを作成
CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(100),
    role VARCHAR(20),
    created DATETIME DEFAULT NULL,
    modified DATETIME DEFAULT NULL
);
bakeでコントローラー、モデル、ビューを作成
sh app/App/Console/cake bake model Users
sh app/App/Console/cake bake controller Users
sh app/App/Console/cake bake view Users

実装

app/App/Controller/UsersController.php
<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\Error\NotFoundException;
use Cake\Event\Event;
/**
 * Users Controller
 *
 * @property App\Model\Table\UsersTable $Users
 */
class UsersController extends AppController {

    public function beforeFilter(Event $event){
        // 上位クラスの機能を使用
        parent::beforeFilter($event);
        // ユーザーによる登録とログアウトを許可する
        $this->Auth->allow('add', 'logout');

    }

/**
 * Index method
 *
 * @return void
 */
	public function index() {
		$this->set('users', $this->paginate($this->Users));
	}

/**
 * View method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
	public function view($id = null) {

        if($id == null){
            throw new NotFoundException(__('Invalid Error'));
        }

		$user = $this->Users->get($id, [
			'contain' => []
		]);
		$this->set('user', $user);
	}

/**
 * Add method
 *
 * @return void
 */
	public function add() {
		$user = $this->Users->newEntity($this->request->data);
		if ($this->request->is('post')) {
            $_password = $user->get('password');
            $user->set('password', $user->_setPassword($_password));

			if ($this->Users->save($user)) {
				$this->Session->setFlash(__('The user has been saved.'));
				return $this->redirect(['action' => 'index']);
			} else {
                $user->set('password', $_password);
				$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
			}
		}
		$this->set(compact('user'));
	}

/**
 * Edit method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
	public function edit($id = null) {
		$user = $this->Users->get($id, [
			'contain' => []
		]);
		if ($this->request->is(['post', 'put'])) {
			$user = $this->Users->patchEntity($user, $this->request->data);
			if ($this->Users->save($user)) {
				$this->Session->setFlash(__('The user has been saved.'));
				return $this->redirect(['action' => 'index']);
			} else {
				$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
			}
		}
		$this->set(compact('user'));
	}

/**
 * Delete method
 *
 * @throws NotFoundException
 * @param string $id
 * @return void
 */
	public function delete($id = null) {
		$user = $this->Users->get($id);
		$this->request->allowMethod('post', 'delete');
		if ($this->Users->delete($user)) {
			$this->Session->setFlash(__('The user has been deleted.'));
		} else {
			$this->Session->setFlash(__('The user could not be deleted. Please, try again.'));
		}
		return $this->redirect(['action' => 'index']);
	}

/**
 * ログインアクション
 * @return \Cake\Network\Response|void
 */
    public function login() {
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                return $this->redirect($this->Auth->redirectUrl());
            }

            $this->Session->setFlash(__('Invalid username or password, try again'));
        }
    }

/**
 * ログアウトアクション
 * @return \Cake\Network\Response|void
 */
    public function logout() {
        return $this->redirect($this->Auth->logout());
    }
}
app/App/Model/Table/UsersTable.php
<?php
namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Validation\Validator;

/**
 * Users Model
 */
class UsersTable extends Table {

/**
 * Initialize method
 *
 * @param array $config The configuration for the Table.
 * @return void
 */
	public function initialize(array $config) {
		$this->table('users');
		$this->primaryKey(['id']);
		$this->addBehavior('Timestamp');

	}

/**
 * Default validation rules.
 *
 * @param \Cake\Validation\Validator $validator
 * @return \Cake\Validation\Validator
 */
	public function validationDefault(Validator $validator) {
		return $validator
            ->notEmpty('username', 'A username is required')
            ->notEmpty('password', 'A password is required')
            ->notEmpty('role', 'A password is required')
            ->add('role', 'inList', [
                'rule' => ['inList', ['admin', 'author']],
                'message' => 'Please enter a valid role'
            ]);

	}

}
app/App/Model/Entity/User.php
<?php
namespace App\Model\Entity;

use Cake\ORM\Entity;
use Cake\Auth\SimplePasswordHasher;

/**
 * User Entity.
 */
class User extends Entity {

/**
 * Fields that can be mass assigned using newEntity() or patchEntity().
 *
 * @var array
 */
	protected $_accessible = [
		'username' => true,
		'password' => true,
		'role' => true,
	];

/**
 * パスワードをハッシュ化
 * @param $password
 * @return string
 */
    public function _setPassword($password) {
        $_password = (new SimplePasswordHasher)->hash($password);
        return $_password;
    }

}
app/App/Template/Users/add.ctp
<div class="users form">
<?= $this->Form->create($user); ?>
	<fieldset>
		<legend><?= __('Add User'); ?></legend>
	<?php
		echo $this->Form->input('username');
		echo $this->Form->input('password');
		echo $this->Form->input('role', [
		    'options' => ['admin' => 'Admin', 'author' => 'Author']
	    ]);
	?>
	</fieldset>
<?= $this->Form->button(__('Submit')); ?>
<?= $this->Form->end(); ?>
</div>
<div class="actions">
	<h3><?= __('Actions'); ?></h3>
	<ul>
		<li><?= $this->Html->link(__('List Users'), ['action' => 'index']); ?></li>
	</ul>
</div>
app/App/Template/Users/edit.ctp

bakeで作成したまま

app/App/Template/Users/index.ctp

bakeで作成したまま

app/App/Template/Users/view.ctp

bakeで作成したまま

app/App/Template/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>
    <?= $this->Form->button(__('Submit')); ?>
<?php echo $this->Form->end(); ?>
</div>
app/App/Controller/AppController.php
<?php
/**
 * 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
 * @since         0.2.9
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
 */
namespace App\Controller;

use Cake\Controller\Controller;
use Cake\Event\Event;

/**
 * Application Controller
 *
 * Add your application-wide methods in the class below, your controllers
 * will inherit them.
 *
 * @link http://book.cakephp.org/3.0/en/controllers.html#the-app-controller
 */
class AppController extends Controller {
    public $components = [
        'Session',
        'Auth' => [
            // ログイン後の画面
            'loginRedirect' => '/users',

            // ログアウト後の画面
            'logoutRedirect' => [
                'controller' => 'Pages',
                'action' => 'display',
                'home'
            ]
        ]
    ];

    public function beforeFilter(Event $event) {
        $this->Auth->allow(['index', 'view']);
    }

}

実行イメージ

ユーザー情報を設定して登録

f:id:m_shige1979:20140614231055p:plain

登録成功後に一覧を表示

f:id:m_shige1979:20140614231107p:plain

ユーザーとパスワードを設定して認証する

f:id:m_shige1979:20140614231116p:plain

ログイン後

f:id:m_shige1979:20140614231123p:plain

まとめ

基本的なログイン方法は理解できた。モデルやセッション、scopeなどを変更して確認してみる。
他のパスワードハッシュ関数もチェックしてみよう

パスワードハッシュについて

Simpleの場合はphpでのパスワードハッシュ関数を使っている感じ…
平文が同じでも結果が異なるのでデータからは平文を予測できないので以前のようなsha1md5よりは安全な感じがする