Yii2: behavior access only ajax

Created on 22 Mar 2015  路  15Comments  路  Source: yiisoft/yii2

hi, i have a question

how can block in the behavior for give access to the action ONLY by ajax ?

any idea or i need create a custom filter for this case

for example
public function behaviors()
{
return [
'ajax' => [
'class' => AjaxFilter::className(),
'only' => ['action1','action2'],
]
];
}
and if you try enter with URL like (http://localhost/controller1/action1 you get 403

ready for adoption enhancement

Most helpful comment

My solution, just check isAjax in matchCallback.

public function behaviors()
{
    return [
        'access' => [
            'class' => 'yii\filters\AccessControl',
            'only' => ['buy-validate', 'buy'],
            'rules' => [
                // allow only AJAX requests using the post Method
                [
                    'allow' => true,
                    'verbs' => ['POST'],
                    'matchCallback' => function () {
                        return Yii::$app->request->getIsAjax();
                    },
                ],
            ],
        ],
    ];
}

All 15 comments

Check for Yii::$app->request->isAjax

@SDKiller i know but is better if we can assign this in the behavior no ?

yii2 no have filter access only ajax no ?

Something like this may work

class AjaxFilter extends \yii\base\ActionFilter
{
    public function beforeAction($action)
    {
        if (Yii::$app->request->isAjax) {

            return parent::beforeAction($action);
        }

        throw new BadRequestHttpException();
    }
}

that will be work, i can suggest add a standard filter for yii2 respect this ?

well if any need this is my class

<?php

namespace common\components\filters;

use Yii;
use yii\base\ActionEvent;
use yii\base\ActionFilter;
use yii\web\Controller;
use yii\web\ForbiddenHttpException;

class AjaxAccess extends ActionFilter
{


public $defaultUrl = ['site/index'];

/**
 * Declares event handlers for the [[owner]]'s events.
 * @return array events (array keys) and the corresponding event handler methods (array values).
 */
public function events()
{
    return [Controller::EVENT_BEFORE_ACTION => 'beforeAction'];
}

/**
 * @param ActionEvent $event
 * @return boolean
 * @throws MethodNotAllowedHttpException when the request method is not allowed.
 */
public function beforeAction($event)
{
    if (Yii::$app->request->isAjax)
        return parent::beforeAction($event);
    else
        $this->denyAccess(Yii::$sapp->uer);
}

/**
 * Denies the access of the user.
 * The default implementation will redirect the user to the login page if he is a guest;
 * if the user is already logged, a 403 HTTP exception will be thrown.
 * @param Yii\web\User $user the current user
 * @throws Yii\web\ForbiddenHttpException if the user is already logged in.
 */
protected function denyAccess($user)
{
    if ($user->getIsGuest()) {
        $user->loginRequired();
    } else {
        $this->ajaxOnly();
    }
}

public function ajaxOnly()
{
    if ($this->defaultUrl !== null) {
        $defUrl = (array)$this->defaultUrl;
        if ($defUrl[0] !== Yii::$app->requestedRoute)
            return Yii::$app->getResponse()->redirect($this->defaultUrl);
    }
    throw new ForbiddenHttpException('Only ajax!');
}


}
and in the behavior add

'ajax' => [
                'class' => AjaxAccess::className(),
                'only' => ['list']
            ]

my suggestion is, add a AjaxFilter for define what actions only work in Ajax, can configure in main.php and create a standard for yii2 well is only a idea @qiangxue @samdark

thx for read this suggestion

AjaxFilter would be useful, I think. Writing an if operator each time the AJAX filtering is needed is a little bit verbose.

@maximal i know, :P i show a sample in this case

i propose to use the two already existing filters instead of creating a new one.

'access' => [
    'class' => \yii\filters\AccessControl::className(),
    'only' => ['create', 'update'],
    'rules' => [
        // allow only AJAX requests using the post Method
        [
            'allow' => true,
            'ajax' => true,
            'verbs' => ['POST']
        ],
    ],
]

AjaxFilter would be really useful
+1

+1

beforeAction can do the trick specially when you also need to do extra stuff with ajax requests like changing the response format:

private $_ajaxOnlyActions = ['create-api','create-resource'];

public function beforeAction($action) {
    if (!parent::beforeAction($action)) return false;
    foreach ($this->_ajaxOnlyActions as $action) {
        if ($this->action->id === $action) {

            if (Yii::$app->request->isAjax === false)
                throw new \yii\web\BadRequestHttpException();

            // all other ajax related stuff
            Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        }
    }
    return true;
}

limiting access to calls either ajax or non-ajax can be useful. Its so generic that usecases can be thought of. Imagining:

  • some pages should not be called without ajax
  • some pages should be called by ajax only

My solution, just check isAjax in matchCallback.

public function behaviors()
{
    return [
        'access' => [
            'class' => 'yii\filters\AccessControl',
            'only' => ['buy-validate', 'buy'],
            'rules' => [
                // allow only AJAX requests using the post Method
                [
                    'allow' => true,
                    'verbs' => ['POST'],
                    'matchCallback' => function () {
                        return Yii::$app->request->getIsAjax();
                    },
                ],
            ],
        ],
    ];
}

Because for use yii\filters\AccessControl need user component and in some use case this component was may not be, you must write your filter like this => https://github.com/yiisoft/yii2/issues/4793#issuecomment-292174430

Was this page helpful?
0 / 5 - 0 ratings