4

編集:大量のコードで申し訳ありません。何が起こっているのか正確にはわからないので、安全のためにさらに追加しました。

私は現在、中央認証サービスにファームアウトするログインページを持っています。ユーザーの権限チェックを行いたいと思います。ユーザーがログインしていない場合は、ログイン ページにリダイレクトし、ログイン ページにリダイレクトさせて、最初に実行していたアクションを実行させ、アクセス チェックを再度実行します。許可がない場合は、アクセスが拒否されたページにリダイレクトしたいと考えています。

これまでに行ったことは次のとおりです。

この行を my に追加しましたapplication.ini:

resources.frontController.actionHelperPaths.Cas_Controller_Action_Helper = APPLICATION_PATH "/controllers/helpers"

ファイルを作成しました$/application/controllers/helpers/PermissionRequire.php:

<?php
/**
 * This class is used in order to require that a user have a given privilege before continuing.
 *
 * @copyright 2011 Case Western Reserve University, College of Arts and Sciences
 * @author Billy O'Neal III (bro4@case.edu)
 */

class Cas_Controller_Action_Helper_PermissionRequire extends Zend_Controller_Action_Helper_Abstract
{
    /**
     * Cleans up the supplied list of privileges. Strings are turned into the real privilege objects (Based on name),
     * privilege objects are left alone.
     *
     * @static
     * @param array|Privilege|string $privileges
     * @return array
     */
    private static function CleanPrivileges($privileges)
    {
        if (!is_array($privileges))
        {
            $privileges =
                    array
                    (
                        $privileges
                    );
        }
        $strings = array_filter($privileges, 'is_string');
        $objects = array_filter($privileges, function($o)
        {
            return $o instanceof Privilege;
        });
        $databaseObjects = PrivilegeQuery::create()->filterByName($strings)->find();
        return array_combine($objects, $databaseObjects);
    }

    /**
     * Generic implementation for checking whether a user can visit a page.
     * @param Privilege|string|array $privileges Any number of privileges which are required to access the given
     *                                           page. If ANY privilege is held by the user, access is allowed.
     * @param AccessControlList The acl which is being checked. Defaults to the application.
     */
    public function direct($privileges, $acl = null)
    {
        $privileges = self::CleanPrivileges($privileges);
        if ($acl === null)
        {
            $acl = AccessControlListQuery::getApplication();
        }
        $redirector = $this->getActionController()->getHelper('redirector');
        /** @var Zend_Controller_Action_Helper_Redirector $redirector */
        $redirector->setCode(307);
        if (Cas_Model_CurrentUser::IsLoggedIn() && (!Cas_Model_CurrentUser::AccessCheck($acl, $privileges)))
        {
            $redirector->gotoSimple('accessdenied', 'login');
        }
        else
        {
            $returnData = new Zend_Session_Namespace('Login');
            $returnData->params = $this->getRequest()->getParams();
            $redirector->setGotoSimple('login', 'login');
            $redirector->redirectAndExit();
        }
    }
}

そして、これが LoginController です。

<?php

/**
 * LoginController - Controls login access for users
 */

require_once 'CAS.php';

class LoginController extends Zend_Controller_Action
{
    /**
     * Logs in to the system, and redirects to the calling action.
     *
     * @return void
     */
    public function loginAction()
    {
        //Authenticate with Login.Case.Edu.
        phpCAS::client(CAS_VERSION_2_0, 'login.case.edu', 443, '/cas', false);
        phpCAS::setNoCasServerValidation();
        phpCAS::forceAuthentication();

        $user = CaseIdUser::createFromLdap(phpCAS::getUser());
        Cas_Model_CurrentUser::SetCurrentUser($user->getSecurityIdentifier());

        $returnData = new Zend_Session_Namespace('Login');
        /** @var array $params */
        $redirector = $this->_helper->redirector;
        /** @var Zend_Controller_Action_Helper_Redirector $redirector */
        $redirector->setGotoRoute($returnData->params, 'default', true);
        $returnData->unsetAll();
        $redirector->redirectAndExit();
    }

    /**
     * Logs the user out of the system, and redirects them to the index page.
     *
     * @return void
     */
    public function logoutAction()
    {
        Cas_Model_CurrentUser::Logout();
        $this->_helper->redirector->gotoRoute('index','index', 'default', true);
    }

    /**
     * Returns an access denied view.
     *
     * @return void
     */
    public function accessdeniedAction()
    {
        //Just display the view and punt.
    }
}

問題は、ユーザーをリダイレクトする URL を準備しているログイン コントローラーで、「params」がnull. また、 を呼び出しているコントローラーへの POST データがある場合、これは機能しません$this->_helper->permissionRequire(SOME PRIVILEGE)

リクエストの状態全体を保存し、そのリクエストと完全に一致するリダイレクトを作成するより良い方法はありますか?

PS ああ、そのヘルパーを使用したコントローラーの例を次に示します。

<?php

/**
 * Serves as the index page; does nothing but display views.
 */

class IndexController extends Zend_Controller_Action
{
    public function indexAction()
    {
        $renderer = $this->getHelper('ViewRenderer');
        /** @var $renderer Zend_Controller_Action_Helper_ViewRenderer */
        if (Cas_Model_CurrentUser::IsLoggedIn())
        {
            $this->_helper->permissionRequire(Cas_Model_Privilege::GetLogin());
            $this->render('loggedin');
        }
        else
        {
            $this->render('loggedout');
        }
    }
}
4

4 に答える 4

2

あなたはリクエストの POST 状態を保存することに非常に熱心であり、私自身もこれと同じ考えで長い間遊んでいるので、次のようなものはどうでしょうか。ただし、まだテストされていないので、保存されたリクエストをこのように設定して実際に期待どおりに機能するかどうかの結果を聞きたいです. (現時点でこれをテストするのが面倒です、ごめんなさい)。

構成 ini で:

resources.frontController.plugins[] = "Cas_Controller_Plugin_Authenticator"

プラグインは次のとおりです。

class Cas_Controller_Plugin_Authenticator
    extends Zend_Controller_Plugin_Abstract
{
    public function routeStartup( Zend_Controller_Request_Abstract $request )
    {
        if( Zend_Auth::getInstance()->hasIdentity() )
        {
            if( null !== $request->getParam( 'from-login', null ) && Zend_Session::namespaceIsset( 'referrer' ) )
            {
                $referrer = new Zend_Session_Namespace( 'referrer' );
                if( isset( $referrer->request ) && $referrer->request instanceof Zend_Controller_Request_Abstract )
                {
                    Zend_Controller_Front::getInstance()->setRequest( $referrer->request );
                }
                Zend_Session::namespaceUnset( 'referrer' );
            }
        }
        else
        {
            $referrer = new Zend_Session_Namespace( 'referrer' );
            $referrer->request = $this->getRequest();
            return $this->_redirector->gotoRoute(
                array(
                    'module' => 'default',
                    'controller' => 'user',
                    'action' => 'login'
                ),
                'default',
                true
            );
        }
    }
}

プラグインはrouteStartup、ユーザーが認証されているかどうかを確認する必要があります。

  • ユーザーがそうでない場合: 現在のリクエスト オブジェクトをセッションに保存し、UserController::loginAction(). (下記参照)
  • ユーザーが IS の場合: セッションから保存されたリクエスト オブジェクトを取得し (利用可能な場合、およびユーザーがログインしたばかりの場合)、frontController 内の現在のリクエスト オブジェクトを置き換えます (ルーターにプロキシする必要があります)。

全体として、どのモジュール/コントローラー/アクションパラメーターが認証と承認を必要とするかを決定するための柔軟性が必要な場合 (私はあなたが望んでいると思います)、おそらくチェックの一部をrouteStartup: つまりrouteShutdown,dispatchLoopStartupまたはpreDispatch. その時までに、アクション パラメータがわかっているはずだからです。追加のセキュリティ対策として、元のリクエストと置換リクエストのアクション パラメータ (モジュール/コントローラ/アクション) を比較して、保存された正しいリクエストを処理しているかどうかを判断することもできます。

$request->setDispatched( false )さらに、一部またはすべてのフックで、新しいリクエスト オブジェクトを設定する必要がある場合があります。ただし、完全にはわかりません: docsを参照してください。

次に、ログイン コントローラの例を示します。

class UserController
    extends Zend_Controller_Action
{
    public function loginAction()
    {
        $request = $this->getRequest();
        if( $request->isPost() )
        {
            if( someAuthenticationProcessIsValid() )
            {
                if( Zend_Session::namespaceIsset( 'referrer' ) )
                {
                    $referrer = new Zend_Session_Namespace( 'referrer' );
                    if( isset( $referrer->request ) && $referrer->request instanceof Zend_Controller_Request_Abstract )
                    {
                        return $this->_redirector->gotoRoute(
                            array(
                                'module' => $referrer->request->getModuleName(),
                                'controller' => $referrer->request->getControllerName(),
                                'action' => $referrer->request->getActionName(),
                                'from-login' => '1'
                            ),
                            'default',
                            true
                        );
                    }   
                }

                // no referrer found, redirect to default page
                return $this->_redirector->gotoRoute(
                    array(
                        'module' => 'default',
                        'controller' => 'index',
                        'action' => 'index'
                    ),
                    'default',
                    true
                );
            }
        }

        // GET request or authentication failed, show login form again
    }
}

ただし、セキュリティ上の理由から、'from-login' クエリ文字列変数の代わりに有効期限ホップ 1 のセッション変数を設定することをお勧めします。

最後に、これをすべて言いました。そもそもこの動作が本当に必要かどうかを徹底的に検討することをお勧めします。もちろんご存知のように、POST リクエストは通常​​、機密性の高い状態変更操作 (作成、削除など) を禁止します。ユーザーが通常、ログイン直後 (セッションが期限切れになった後) にこの動作を期待しているのかどうかはわかりません。また、これがアプリケーション自体の予期しない動作につながる可能性のあるシナリオについて考えることもできます。今はまだ具体的なことは思い浮かびませんが、もう少し考えれば思いつくことができると思います。

HTH

EDIT
ログインプロセスの後に正しいリダイレクトアクションを追加するのを忘れました

于 2011-03-05T09:12:44.723 に答える
1

GETリクエストの場合、それは非常に簡単です。認証がない場合は、リクエストのURLをセッションに保存し、ログインにリダイレクトします。ログイン後、保存されたリクエストURLがある場合は、そこに送信します。認証は成功したがアクセス権限が失敗した場合は、すぐにアクセス拒否に送信してください。

スティッキーポイントはPOSTリクエストです。リクエストURLのみを保存すると、投稿のデータが失われます。これらのパラメータとリクエストタイプ(「POST」)もセッションに保存した場合でも、ログイン後のリダイレクトがPOSTリクエストとして機能することは可能ですか?私にとって、それが質問の本質です。

method="post"1つの解決策は、ログイン後のリダイレクトを、元の投稿データがすべて非表示フィールドに隠されたフォーム(を含む)を含む遷移ページにリダイレクトすることです。次に、送信ボタンを非表示にしてフォームを送信するオンロードJavaScriptを実行します。javascriptがない場合、JavaScriptは-比較的-優雅に低下します。ユーザーは送信ボタンをクリックするだけです。

それはうまくいくでしょうか?

于 2011-03-04T13:37:26.867 に答える
0

ユーザーがログに記録されているかどうかに基づいて 1 つのコントローラーを保護するために、プロジェクトで使用しているものを投稿しました。次のコードを使用して、ログインのチェック中に特別な権限をチェックすることもできます。ユーザーが適切な権限を持っていない場合は、エラー コントローラーにリダイレクトするか、エラー ビューを表示します。

このコードには、質問されている内容の例があります-別のコントローラーにリダイレクトするときに現在の URL をパラメーターに保持し、成功時に同じ URL にリダイレクトします。

class ProtectedController extends Zend_Controller_Action {

    public function indexAction() {

    if (Zend_Auth::getInstance()->hasIdentity()) {
               //Show the content
       } else {
                $this->_redirect('user/login/?success=' . $this->getRequest()->getRequestUri());
            }
        }

    }

そしてユーザーコントローラー

class UserController extends Zend_Controller_Action {

    public function loginAction() {
            $returnURL = $this->_getParam('success', '/');
            if (checkAuthenticity()) {
                $this->_redirect($returnURL);
            }
      }
}
于 2011-03-04T09:36:27.477 に答える