Search code examples
phpyii2yii2-advanced-appphp-7.4

Yii2: do not redirect to login for a certain action in controller


I have a custom controller and I'm trying to define an action in the controller that could be accessed by the guest users. My controller code is the following:

class MyCustomController extends Controller
{
    ...
    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'delete' => ['POST'],
                ],
            ],
            'access' => [
                'class' => AccessControl::class,
                'only' => ['live'],
                'rules' => [
                    [
                        'allow' => true,
                        'actions' => ['live'],
                        'roles' => ['?'],
                    ],
                ]
            ]
        ];
    }


    /**
     * Live action.
     * @return mixed
     */
    public function actionLive()
    {
        return $this->render('live');
    }
...
}

And the view code is this:

<?php

echo 'We are live!!';

?>

I also have this setting in frontend/config/main.php

return [
...
'as beforeRequest' => [
        'class' => 'yii\filters\AccessControl',
        'rules' => [
            [
                'actions' => ['login', 'error'],
                'allow' => true,
            ],
            [
                'allow' => true,
                'roles' => ['@'],
            ],
        ],
    ],
...
]

When I try to access the page http://my-webapp/my-custom/live as an authenticated user I get the message Forbidden (#403) which is ok (although displaying it for the authenticated users would be perfectly ok too).

But when I access that page as a guest user I get redirected to the login page. I just want to disable the redirect for this particular action and just let the guest users see that view.


Solution

  • You are applying AccessControl filter twice.

    First filter is set for Application so it is applied for each request with following rules:

    1. If the action id is "login" or "error" allow any user.
    2. Allow logged in users
    3. Deny any other request.

    The second filter is for MyCustomController and it's set to apply only for requests to action live of that controller with following rules:

    1. Allow any user who is not logged in.
    2. Deny any other request.

    So when request comes from user who is logged in, the request is stopped by second filter and the 403 error is displayed. When request comes from guest user it is stopped by first filter and user is redirected to login page.

    To allow guests access your action you should add exception to first filter to make sure only second AccessControl filter is applied:

    return [
        //...
        'as beforeRequest' => [
            'class' => 'yii\filters\AccessControl',
            'except' => ['my-custom/live'],
            'rules' => [
                [
                    'actions' => ['login', 'error'],
                    'allow' => true,
                ],
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
            ],
        ],
    ...
    ];
    

    Actually, if you are OK with allowing any user to see the my-custom/live there is no need for the second AccessControl filter. Just setting the exception in the first (application wide) filter will be enough.