DBからの情報取得ではなく、外部のAPIにアクセスして認証したかったので
Authコンポーネントをカスタマイズしてみた。
画面遷移としては、ユーザー名(メールアドレス)とパスワードを入力し、
APIに接続してOKならログインする、というもの。
Authenticate
おーせんてぃけーと。
上記で書いた通り、フォームから送信されたユーザー名とパスワードを使用してログインするので、
FormAuthenticate
を継承する。
オーバーライドする関数は、authenticate
と_findUser
。
/app/Controller/Component/Auth/UseAPIAuthenticate.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| <?php
App::uses('FormAuthenticate', 'Controller/Component/Auth');
class UseAPIAuthenticate extends FormAuthenticate {
public function authenticate(CakeRequest $request, CakeResponse $response)
{
//コンポーネントの設定を読み込む
$userModel = $this->settings['userModel'];
list(, $model) = pluginSplit($userModel);
$fields = $this->settings['fields'];
if (!$this->_checkFields($request, $model, $fields)) {
return false;
}
return $this->_findUser(
$request->data[$model][$fields['username']],
$request->data[$model][$fields['password']]
);
}
public function _findUser($username, $password = null)
{
// ログイン実施
$this->user = null;
$ret = ClassRegistry::init('Api')->login($username, $password);
if (! $ret) {
//なんらかのログインエラー
return false;
}
//ユーザーデータ。中身はニーズに合わせて
$result = Array(
"username" => $username,
"result" => $ret
);
return $result;
}
}
|
APIに接続する処理は、Apiというモデルに記述しているとする。
コンポーネントからモデルを使用するのはあまりよくないともどこかで見たが、標準のAuthコンポーネントも使用していたのでよしとする。
その際の使用方法は以下のようになる。
ClassRegistry::init('Api')
ログイン成功後、返却するデータの中身は、配列である必要があるよう。
true
とだけ返してても認証されなかった。
AppController
AppControllerにて、上記のAuthコンポーネントの設定を書く。
/app/Controller/AppController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| <?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $uses = array('User', 'Api');
public $components = array(
'Session',
'Auth' => array(
'authenticate' => array(
'UseAPI' => array(
'userModel' => 'User',
'fields' => array(
'username' => 'email'
)
)
)
)
);
....略....
}
|
作成したクラスファイル名が、UseAPIAuthenticate
の場合は、UseAPI
と、Authenticateを引いて指定する。
これは実際にCakeのAuthコンポーネント内で、以下のように指定されているため。
/lib/Cake/Controller/Component/AuthComponent.php
795行目
$className = $class . 'Authenticate';
で、使用するモデルは、User
とし、今回はメールアドレスでのログインということで、username
にemail
を使用する指定をしている。
UsersController
で、ログインページで実行される処理をUsersController
に書く。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| <?php
App::uses('AppController', 'Controller');
class UsersController extends AppController
{
public $uses = array('User', 'Api');
public function beforeFilter()
{
$this->Auth->allow('login', ...認証除外ページ);
parent::beforeFilter();
}
/**
* ログイン
*/
public function login()
{
//POST値がある?
if (! $this->request->is('post')) {
// ログインフォームを表示
$this->logout(); //ログアウトしてログインページを表示させる処理
return;
}
/// authコンポーネント使用
//ログイン
$result = $this->Auth->login(); //trueかfalseが返ってくる
$data = $this->Auth->user(); //UseAPIAuthenticateで設定したユーザーデータを取得出来る
if (!$result) {
$this->Session->setFlash(__('ユーザ名もしくはパスワードが正しくありません'));
return;
}
//トップページへ
$this->redirect(array('action' => 'index'));
}
....略....
}
|
$this->Auth->login()
とするだけでフォームで入力された内容が引き継がれてログイン処理が行われる。
実際の処理は、/lib/Cake/Controller/Component/AuthComponent.php
で行われている。
ログインの結果は、trueかfalesで返ってくるのでfalseの場合はエラーを表示している。
ログイン成功時にセットしたユーザーデータは、$this->Auth->user()
で取得できる。
Model
実際にAPIを使用してログインしている箇所は側だけ。中身は割愛。
/app/Model/Api.php
1
2
3
4
5
6
7
8
9
10
11
| <?php
App::uses('AppModel', 'Model');
class Sf extends AppModel
{
public function login($email, $pw)
{
//何かしらAPIへの接続処理
return $result;
}
}
|
View
最後はビュー。フォーム部分だけ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
| <?php echo $this->Form->create('User', array('novalidate' => true)); ?>
<label>
ログインID<br>
<?php echo $this->Form->input('User.email', array(
'label' => false,
'placeholder' => ''
)); ?>
</label>
<label>
パスワード<br>
<?php echo $this->Form->input('User.password', array(
'type' => 'password',
'value' => '',
'label' => false,
'placeholder' => ''
)); ?>
</label>
<?php echo $this->Session->flash(); // エラーメッセージ ?>
<?php echo $this->Form->submit('ログイン', array(
'class' => 'input-submit',
'div' => false
)); ?>
<?php echo $this->Form->end() ?>
|
nameにあたる、User.email
の部分はCompnentの設定に合わせる。
ちなみに、formタグにある、'novalidate' => true
は、
何も指定しない場合は勝手に、required="required"
がついてしまうので、それを付けない設定を一括で指定している。
バリデーションは他でまとめてしているのでついてないほうがなにかとやりやすい。
まとめ
最初は自前でクッキーなどをチェックしていたのだが、
ページ遷移時の認証機構をcakephpが一括して受け持ってくれるのはかなり楽だった。
参考
カスタム認証オブジェクトの作成 – 認証 — CakePHP Cookbook 2.x ドキュメント
CakePHP 2.4 md5 で Auth認証 – Qiita