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

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

ただいまの
回答率

90.98%

  • PHP

    17813questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • CakePHP

    2129questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

cakephp3で複数認証を実装したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 963

lovelydai

score 20

前提・実現したいこと

こんにちは!
cakephp3.5.1で何かの管理システムを作っています。
ここで、管理者画面とユーザー画面を分け、管理者は管理者ページでログインができ、ユーザーは一般のページでログインさせたいです。つまり、1つのサービスで2つの認証が必要です。

色々探ってみた結果、2.xでは複数認証という形で実装できるとのことでした。(http://www.aipacommander.com/entry/2016/04/27/221317)

しかし、3.xでは上手くできませんでした。Cakephp3のチュートリアルなどをみると、1つのサービスには1つのAppController.phpがあり、それがすべてのControllerに相続されるので別々にログインできませんでした。
また、Routesにprefixを設定すると、Controllerが変わったら(リンクを押すなど)「You are not authorized to access that location.」というエラーが出てしまい、ページが変わらない又はHome(Cakephp3設置時に表示される画面)ページに戻ってしまいます。

Cakephp3で1つのサービスに2つの認証を実装するための手順や設定などがあれば教えていただきたいです。
宜しくお願い致します。

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

You are not authorized to access that location.

該当のソースコード

<?php

namespace App\Controller\Admin;

use App\Controller\AppController;
use Cake\Event\Event;
use Cake\Controller\Component\AuthComponent;

class ContractController extends AppController
{
    /**
     * Initialize method for system administrator login
     */
     public function initialize()
     {
       parent::initialize();

       $this->loadComponent('Auth', [
            'authorize' => ['Controller'],
           'loginAction' => [
               'controller' => 'Contract',
               'action' => 'login',
               'prefix' => false
           ],
           'loginRedirect' => [
               'controller' => 'Contract',
               'action' => 'index'

           ],
           'logoutRedirect' => [
               'controller' => 'Contract',
               'action' => 'login'

           ],
           'authenticate' => [
               'Form' => [
                  'userModel' => 'Contract',
                  'fields' => ['username' => 'loginid', 'password' => 'password'],
               ]
           ],
           'flash' => [
                'element' => 'error'
           ],
           'prefix' => 'admin',
           'unauthorizedRedirect' => $this->referer(),
           'authError' => 'ログインできませんでした。ログインしてください。',
       ]);

       // Allow the action
     }

     public function beforeFilter(Event $event)
     {
       parent::beforeFilter($event);

       // ログインせずに接近できるページの設定
       $this->Auth->allow(['logout']);

       // ログイン後セッション情報を収得するためのハンドラー
       $this->set('auth', $this->Auth->user());

     }

     /**
      * Login method for system administrator login
      */

      public function login()
      {
        //$admin = $this->Contract->newEntity();
        if ($this->request->is('post')) {
            //$admin = $this->Contract->patchEntity($admin, $this->request->data);
            $contract = $this->Auth->identify();
            if ($contract) {
                $this->Auth->setUser($contract);
                return $this->redirect($this->Auth->redirectUrl());
            } else {
                $this->Flash->error(__('ログインIDとパスワードをご確認ください。'));
            }
        }
        // $this->set(compact($admin));
        // $this->set('_serialize', ['admin']);
      }

      public function logout()
      {
        $this->request->session()->destroy();
        $this->Flash->success('成功的にログアウトしました。');
        return $this->redirect($this->Auth->logout());
      }

      public function isAuthorized($contract = null)
      {
        // todo..
        if (!$this->request->getParam('prefix')) {
               return true;
         }
         return false;
      }


    public function index()
    {
        $contract = $this->paginate($this->Contract);

        $this->set(compact('contract'));
        $this->set('_serialize', ['contract']);
    }

 // CRUD(Add,Edit,View,Delete)ソースは省略
}
<?php

namespace App\Controller\Admin;

use App\Controller\AppController;
use Cake\Event\Event;

class ContractinfoController extends AppController
{

   public function initialize()
   {
     parent::initialize();

     $this->loadComponent('Auth', [
                 'authorize' => ['Controller'],

             ]);

     // Allow the action
   }

   public function beforeFilter(Event $event)
   {
     parent::beforeFilter($event);

   }

   public function isAuthorized($contract = null)
   {
     // todo..
        return true;

   }

    public function index()
    {
        $contractinfo = $this->paginate($this->Contractinfo);

        $this->set(compact('contractinfo'));
        $this->set('_serialize', ['contractinfo']);
    }

    // CRUD(Add,Edit,View,Delete)ソースは省略
}
<?php

use Cake\Core\Plugin;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;

Router::defaultRouteClass(DashedRoute::class);

Router::scope('/', function (RouteBuilder $routes) {

    $routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);

     $routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);

    /**
     *  一般用トップページ用
     */
      //  $routes->connect('/:controller', ['action' => 'index', 'prefix' => 'front'], ['routeClass' => 'DashedRoute']);
      //  $routes->connect('/:controller/:action/*', ['prefix' => 'front'], ['routeClass' => 'DashedRoute']);

      $routes->connect('/admin', ['controller' => 'Contract', 'action' => 'index', 'prefix' => 'admin']);
    //  $routes->connect('/admin:controller', ['action' => 'index', 'prefix' => 'admin'],['routeClass' => 'DashedRoute']);
     //$routes->connect('/admin/Contactinfo', ['controller' => 'Contractinfo', 'action' => 'index', 'prefix' => 'admin']);

     //$routes->fallbacks(DashedRoute::class);
});
Router::prefix('admin', function ($routes) {
    $routes->fallbacks('DashedRoute');
});

Plugin::routes();

試したこと

・prefixを使ってフォルダー構造を変更してみました。
・2.X基準で書かれた複数認証のやり方をまねしてみました。

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

・Php 7.0

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • icchii

    2017/09/11 13:51 編集

    コードは、シンタックスハイライトしてください https://teratail.com/help/question-tips#questionTips3-5-1

    キャンセル

  • lovelydai

    2017/09/11 15:26

    ありがとうございます。シンタックスハイライトを適用しました。

    キャンセル

回答 1

checkベストアンサー

+1

自分は、prefixルーティングを使って、以下のようにAppControllerのinitialize()内で分岐して、それぞれ認証設定をする方法で実現しましたよ。
sessionKeyがかぶっていると、両方のログインができなくなるので、管理者側は変更しています。

class AppController extends Controller
{
    public function initialize()
    {
        parent::initialize();
        if ($this->request->prefix == 'admin') {
            $this->loadComponent('Auth', [
                // 管理者の認証設定
            ]);
            $this->Auth->sessionKey = 'Admin';
        } else {
            $this->loadComponent('Auth', [
                // 一般ユーザの認証設定
            ]);
        }
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/09/11 19:46

    ご回答誠にありがとうございます!今日一日中ずっと悩んでいて、私は appControllerを継承し、それぞれAdminsAppControllerとUsersAppControllerの2つに分け、必要なControllerにExtendsする形でやろうとしましたが、セッションキーがかぶる問題でなかなk上手くできませんでした。頂いたアドバイスで実装したら、異常無しで動きました。また色々教えてください。ありがとうございます!

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る

  • PHP

    17813questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • CakePHP

    2129questions

    CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。