CakePHPの認証でアカウントロックを実装してみる

はじめに

アカウントロックって実装したことないなと思ったので
CakePHPで実装してみます。

エラー回数10で認証できないようにする

  • usersテーブルにエラー回数を追加
CREATE TABLE users
(
  id bigserial NOT NULL,
  username character varying(64),
  password character varying(256),
  role character varying(32),
  creaated timestamp with time zone,
  modified timestamp with time zone,
  error_count integer NOT NULL,
  CONSTRAINT users_pkey PRIMARY KEY (id)
);
  • error_countが10以上ならロックされましたエラーにする

AppController.phpでauthenticateの検索条件にerror_countが10未満を追加します。

    public $components = array(
        'Session',
        'Auth' => array(
            'loginRedirect' => array('controller' => 'books', 'action' => 'index'),
            'logoutRedirect' => array('controller' => 'pages', 'action' => 'display', 'home'),
            'authenticate' => array(
                'Form' => array(
                    'passwordHasher' => 'Slow',
                    'scope' => array( 'User.error_count <' => 10)                )
            )
        )
    );
  • アカウントロックだとわかるようにUsersController.phpのlogin()を修正する。

UsersController.phpのlogin()抜粋

    public function login() {
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                $this->redirect($this->Auth->redirect());
            } else {
                $options = array('conditions' => array('User.username' => $this->request->data['User']['username'], 'User.error_count >=' => 10));
                $lockedUser = $this->User->find('first', $options);
                if (!empty($lockedUser)) {
                    $this->Session->setFlash(__('Account is locked.'));
                } else {
                    $this->Session->setFlash(__('Invalid username or password, try again'));
                }
            }
        }
    }
  • 認証失敗でerror_count++するためUser.phpに追加しUsersController.phpのlogin()で呼ぶ。

User.phpにincrementErrorCount()を追加

    public function incrementErrorCount($target) {
        $data = array('id' => $target['id'], 'error_count' => $target['error_count'] + 1);
        $fields = array('error_count');
        $this->save($data, false, $fields);
    }

UsersController.phpのlogin()抜粋

    public function login() {
        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                $this->redirect($this->Auth->redirect());
            } else {
                $options = array('conditions' => array('User.username' => $this->request->data['User']['username']));
                $lockedUser = $this->User->find('first', $options);
                if (!empty($lockedUser) && $lockedUser['User']['error_count'] >= 10) {
                    $this->Session->setFlash(__('Account is locked.'));
                } else {
                    if (!empty($lockedUser)) {
                        $this->User->incrementErrorCount($lockedUser['User']);
                    }
                    $this->Session->setFlash(__('Invalid username or password, try again'));
                }
            }
        }
    }

まとめ

これで10回続けてエラーの場合アカウントがロックされるようになりました。
「ロック解除は管理者に連絡してください」って運用じゃだめですよね。
一定時間たったらアカウントロック解除しないといけないですね。

気が向いたらやってみます。