前書き
パスワードを使わずにAuthComponentを使ったログインを実装したのでそのメモ書き
1つのテーブルだけじゃなくて複数のテーブルのデータからログインできる様に実装しています。
イメージとして
荷物の再配達のサイトとして
電話番号と再配達番号の二つで再配達依頼ができる様にするイメージです。
開発環境
PHP 3.6
CakePHP 3.8
※注意点
AuthComponent は CakePHP4.0.0以降では非推奨になり、authorizationとauthenticationプラグインに置き換えられます。
引用元:CakePHP公式(AuthComponent)
最初に行き着く答え
class AppController extends Controller
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler', [
'enableBeforeRedirect' => false,
]);
$this->loadComponent('Flash');
//ログインの項目はCustomersControllerのloginメソッドに書いてある
$this->loadComponent('Auth',[
'authenticate', [
'Form' => ['userModel' => 'Deliveries'],
'fields' => [
'delivery_no' => 'delivery_no',
'user_phone' => 'user_phone',
],
//ログイン処理を行う場所
'loginAction' => [
'controller' => 'Deliveries',
'action' => 'login'
],
//ログイン後のリダイレクト先
'loginRedirect' => [
'controller' => 'Deliveries',
'action' => 'list'
],
//ログインしていないのにログイン後ページを開いた時のアラート
'authError' => __('ログインしてください。')
]);
}
}
多分こんな感じで'userModel'を用いてAppControllerを書く様になるんですが上手くいかない。
レコード内容通りにPOSTしても上手くいかないはずです。
原因
protected function _findUser($username, $password = null)
{
$result = $this->_query($username)->first();
if ($result === null) {
// Waste time hashing the password, to prevent
// timing side-channels. However, don't hash
// null passwords as authentication systems
// like digest auth don't use passwords
// and hashing *could* create a timing side-channel.
if ($password !== null) {
$hasher = $this->passwordHasher();
$hasher->hash($password);
}
return false;
}
.
.
.
}
AuthComponentの中身を見てみると2つ目の引数(?)はハッシュ化しているのを前提に作られているため、ハッシュ化されていないデータをログイン内容に含めても上手くいかない様になっています。
ここの記述を書き直す、もしくは参照するデータをハッシュ化しても良いんですが、cakephpのコアな部分を書き直すのは嫌だしデータベースを直接いじるのはリスクでしか無いので別案で実装をして行きます。
本編
/**
* login - ログイン処理を行う
*
*/
public function login()
{
$this->autoRender = false;
//POST
if ($this->request->is('post')) {
$post_date = $this->request->getData();
//ログインしたい内容をPOSTされた情報を元にfindしてしまう
$login_user = $this->Deliveries->find()
->contain(['Deliveries'])
->where([
'Deliveries.delivery_no' => $post_date['delivery_no'],
'Customers.user_phone' => $post_date['user_phone']
])
->first();
//検索した結果データがあった場合
if(!empty($login_user)){
//ユーザー情報をセッションに保存
$this->Auth->setUser($login_user->toArray());
return $this->redirect($this->Auth->redirectUrl());
}else{
//元にいたページに戻す
return $this->redirect($this->referer());
}
}
}
<?php
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Controller\Component\AuthComponent;
use Cake\Event\Event;
use Cake\ORM\TableRegistry;
/**
* Application Controller
*/
class AppController extends Controller
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler', [
'enableBeforeRedirect' => false,
]);
$this->loadComponent('Flash');
//ログインの項目はCustomersControllerのloginメソッドに書いてある
$this->loadComponent('Auth',[
//ログイン処理を行う場所
'loginAction' => [
'controller' => 'Deliveries',
'action' => 'login'
],
//ログイン後のリダイレクト先
'loginRedirect' => [
'controller' => 'Deliveries',
'action' => 'list'
],
//ログインしていないのにログイン後ページを開いた時のアラート
'authError' => __('ログインしてください。')
]);
}
}
やったことはログインするときにPOSTされた内容を元にSQL(find関数)でデータベースを探させて見つかったらそれをセッションに持たすだけ。
AppControllerに書いていた「authenticate」は不要なので削除。
参考サイト
CakePHP公式サイト(AuthComponent - 手動でのユーザーログイン)
公式を読むって大切ですよね。読みづらいけどしれっと大事な事と書いてますし。