質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.10%

cakephp3 フォーム認証(サイト全体認証から階層認証に変えたい場合)

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,582

holic

score 119

前提・実現したいこと

cakephpを勉強中のものです。本当に初歩なことだと思いますがご教示いただけましたら幸いです。
フォーム認証を作成しました。

AppController.phpのinitializeメソッド記述

{
    parent::initialize();
    $this->loadComponent('Flash');
    //認証
    $this->loadComponent('Auth',[
    'authenticate' => [
        'Form' => [
            'fields' => [
                'username' => 'email',
                'password' => 'password'
            ]
        ]
    ],
    'loginAction' => [
        'controller' => 'Users',
        'action' => 'login'
    ]
]);
}

Usersコントローラーに、loginアクションを追加。

/**
 * ログインページ
 * @return type
 */
public function login()
{
    if($this->request->is('post')){
        $user = $this->Auth->identify();
        if($user){
            $this->Auth->setUser($user);
            return $this->redirect($this->Auth->redirectUrl());
        }
        $this->Flash->error('ユーザー名かパスワードが間違い');
    }
}

Template\Users\login.ctp 

<h1>Login</h1>
<?= $this->Form->create() ?>
<?= $this->Form->input('email') ?>
<?= $this->Form->input('password') ?>
<?= $this->Form->button('Login') ?>
<?= $this->Form->end() ?>

これでサイト全体には問題なくログイン認証が成功できました。

発生している問題・エラーメッセージ

AppController.phpのinitializeの記述ですが、AppController.phpに書いたことにより、全てのページにログイン認証がかかりました。
例えば、photosという階層直下にだけ認証が欲しい場合はどうしたら良いのかなと考えて、
PhotosController.phpにinitializeメソッドの記述を移動しました、そうしましたら/photos/のページにレンダリングをした際にログイン画面は表示はされましたが、ユーザー名とパスワード入力しましたら、
”$user = $this->Auth->identify();”がエラーですと表示されてしまいました。

イメージ説明
※もちろんサイト全体認証をかけたときにはこのエラーはでませんでした。
initializeの記述をPhotosController.phpに移動したときに発生しました。

あともう一歩な気がしますが、どのように設定したら特定の階層だけ認証ができるようになるのでしょうか。
ご教示願います。

エラーメッセージ

補足情報(言語/FW/ツール等のバージョンなど)

cakephp3系

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

特定の階層だけ認証させるのではなく、
全体に認証を掛けつつ、特定の階層以外を認証解除する方法は以下の通りですがいかがでしょうか?

// すべてのアクションを許可
$this->Auth->allow();

// index アクションのみ許可
$this->Auth->allow('index');

// view と index アクションのみ許可
$this->Auth->allow(['view', 'index']);

使用例:

public function beforeFilter(Event $event) {
    parent::beforeFilter($event);
    $this->Auth->allow();
}


コントローラに記述します。記述したコントローラ内では認証解除状態となります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/23 13:41 編集

    ご回答していただきましてありがとうございます。検索してみましてもこの手法がcakephpでは一般的な手法なのだと理解しました。
    先達の方々に従いこちらの手法で行きたいと考えております。
    補足で質問させてください。


    public function beforeFilter(~
    $this->Auth->allow();
    この記述は各controller.phpで記述する認識で良いのでしょうか。

    今回の使用例でしたら、AppController.phpに認証かけて、PhotosController.phpは特に触らずで、認証をかけたくないParentsController.phpに記述するという使用方法でよろしいのでしょうか。

    もう一点確認点として

    もし各コントローラーで記述ができるのでしたら
    ParentsController.phpの場合は
    $this->Auth->allow('index');

    ChildsController.phpの場合は
    $this->Auth->allow(['view', 'index']);
    と認証領域を制御できるという理解で問題ないでしょうか。

    キャンセル

  • 2017/07/25 02:35

    local環境で試してみました。

    use Cake\Event\Event;

    を付与させることで問題なく動きました、ありがとうございます。

    キャンセル

+1

認証するUsersControllerがAuthコンポーネントをロードしていないので、$user = $this->Auth->identify();でエラーが発生しています。なので、UsersControllerでもAuthロードすればエラーは回避できると思います。

ただし、UsersControllerとPhotosControllerの両方でAuthの設定を書くのはコードが重複してしまいますので、AppControllerでコントローラに応じて、Authをロードするコードを書くと良いかとおもいます。($this->nameでどのコントローラかは判断できます)

if ($this->name == 'Users' || $this->name == 'Photos') {
    $this->loadComponent('Auth');
} 

なお、認証を必要としないページにおいても、認証ユーザの情報(現在ログイン中のユーザ名など)を表示したいのであれば、全ページでAuthをロードする必要があります。その場合、rikさんの回答のように$this->Auth->allow();を使って認証必要の有無を設定する方法がよいでしょう

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/23 13:59

    UsersController.phpにもAuthコンポーネントが必要だったとは全く見落としておりました。ご指摘いただけて誠にありがとうございます。

    $this->nameでどのコントローラーか判断できるのかも初めて知りました、今後このif文の使用頻度は大きそうです。

    icchiiさんの解答は大変勉強になります、(全体認証のやり方に補足もしていただけておりますし、より理解は深まりました)、
    本当はお二方にベストアンサーをつけたいのですが今回はrikさんにベストアンサーをさせていただきます。

    他の方のcakephpの質問に対して
    icchiiさんが的確な回答をされているのをいつも見ております、また今後も私から質問させていただくことがあると思いますがその際はよろしくお願いいたします。

    キャンセル

  • 2017/07/23 14:27

    お役に立てて良かったです。そうですねallow()を使う方法が一般的で自分もいいと思います。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる