Redirect to login for guest users in every controller

Hi! I found that beforeAction() can be used to hold the code to check if the user is not logged in, and then redirect the user to the login page with something like this:

if(Yii::app()->user->isGuest) $this->redirect(Yii::app()->getModule(‘user’)->loginUrl);

But to have it working in the whole site I need to put this code in every beforeAction() in every Controller!

In a backend application the guest user can not even see the app menu, a non autenticated user can only access the login page. It’s a tipical scenario. Every controller should be protected for guest users.

For a backend application this behavior may be desirable for every controller, there is a way to write the code just once, in a single place, instead of adding the beforeAction() to each Controller?

There is a kinda master contoller in your components folder. You can set a beforeFilter there application wide.

The Access Control Filter will do the work for you and redirects to the configured user->loginUrl (config/main.php) if a action is not allowed.

Add the rule


 

             array('deny',

                'users'=>array('?'),

            ),

to your base controller (f.e. ‘Controller’) where all your controllers are inherited from.

See this wiki article too: Access rules to default deny

Joblo, Greg, many thanks! Your suggestion works for me =)

But I found a little issue…

If I deny access to every non autenticated user in every controller, Yii will redirect to the login controller/action. But this controller also has the access denied! This condition creates an infinite loop of redirects to the login form.

I can avoid it explicitly allowing access to every user to the login controller, like this:

        array('allow', // allow authenticated users to access all actions


            'controllers'=>array('user'),


            'actions'=>array('login'),


            'users'=>array('*'),


        ),

but it doesn’t work… If I just define the ‘login’ action (removing the “‘controllers’=>array(‘user’),” line)it works fine, but also defining the controller to narrow the rule will lead to a no-match. Maybe a sintax issue?

If I just specify the login action the system will allow access to any action called "login", no matter the related controller.

Why don’t you override the accessrules from the base-controller in the user-controller?

I wouldn’t add ‘controllers’ to the access rules. Maybe this helps.

Hi Jpablo,

I have a solution, why don’t you check in beforeAction() of controller.

I’ve tried and it works for every Guest users, they will be redirected to login page.




public function beforeAction()

{

       if (Yii::app()->user->isGuest)

            $this->redirect(Yii::app()->createUrl('user/login'));


       //something code right here if user valided

}



Hope that help.

1 Like

For whom who still havent solved this issue , add the following condition before loading the index page at the SiteController file.


public function actionIndex()

	{

		

       if (Yii::app()->user->isGuest)

        $this->redirect(Yii::app()->createUrl('site/login'));

	else

	$this->render('index');

	}

Dear Friends.

We can use a behavior to to acheive the things.

Create ApplicationBehavior.php put inside the components folder.

components/ApplicationBehavior.php




<?php

class ApplicationBehavior extends CBehavior

{	private $_owner;

	

	public function events() 

        {


                    return  array(

			       'onBeginRequest'=>'denyEverything',     

			        

		        );

        }

	

	public function denyEverything()

       {

		$owner=$this->getOwner();

		if($owner->user->getIsGuest())

			$owner->catchAllRequest=array("site/login");

       }

}

?>



Then attach the behavior as a property to the application.

main.php




'behaviors'=>array(

    'class'=>'application.components.ApplicationBehavior',

      ),



Now if user is guest all the requests are landed at site/login.

Regards.

If anyone is having trouble with this and if you tying to force users login before they can view/do anything. You can do something like this:

Forcing login

Pretty much what seenlvasas said.

I use a variation of this and works well. I also added something like this to my main config file to manage sessions.




'components'=>array(

                

            //forces user to login after 20 minutes of inactivity.  

            'session' => array(

               'class' => 'CDbHttpSession',

               'timeout' => 1200,

            ),

	         'user'=>array(

                    // enable cookie-based authentication

                    'class' => 'WebUser',

                    'allowAutoLogin'=>false,

                    'autoRenewCookie' => true,

                    'authTimeout' => 86400, //kills session after 24 hours just in case above fails or if a user clicks remember me it will only last for this duration.

                    'loginUrl' => array('/user/login'),

                ),



here is my exact RequireLogin.php note i’m using yii-user and the captcha image dosen’t render on login but i don’t use it anyways.




<?php

class RequireLogin extends CBehavior

{

    public function attach($owner)

        {

            $owner->attachEventHandler('onBeginRequest', array($this, 'handleBeginRequest'));

        }

        

    public function handleBeginRequest($event)

        {

            $app = Yii::app();

            $user = $app->user;

            $recovery = trim(is_array(Yii::app()->getModule('user')->recoveryUrl) ? Yii::app()->getModule('user')->recoveryUrl[0] : Yii::app()->getModule('user')->recoveryUrl, '/'); //gets recovery url for yii-user

            $registration = trim(is_array(Yii::app()->getModule('user')->registrationUrl) ? Yii::app()->getModule('user')->registrationUrl[0] : Yii::app()->getModule('user')->registrationUrl, '/'); //gets reistraion url for yii-user

            $captchUrl = trim(is_array(Yii::app()->getModule('user')->captchaUrl) ? Yii::app()->getModule('user')->captchaUrl[0] : Yii::app()->getModule('user')->captchaUrl, '/'); //gets captcha url for yii-user..dosen't work?!?

            $request = trim($app->urlManager->parseUrl($app->request), '/');

            $login = trim($user->loginUrl[0], '/');

            $login = trim(is_array($user->loginUrl) ? $user->loginUrl[0] : $user->loginUrl, '/'); //gets loginurl from main config file


            // Restrict guests to public pages.

            $allowed = array($login,$recovery,$registration,$captchUrl);//allows users if not logged in to view only these 4 pages you can add others like above or like array($login,'site/login'); either way works. This is easier than adding to each controller if you only want users to be able to view a few pages w/o logging in.

            if ($user->isGuest && !in_array($request, $allowed))

            $user->loginRequired();

            

            // Prevent logged in users from viewing the login page.

            $request = substr($request, 0, strlen($login));

            if (!$user->isGuest && $request == $login)

            {

            $url = $app->createUrl($app->homeUrl[0]);

            $app->request->redirect($url);

        }

    }

}

?>



My url manager also looks like this (displays urls like : myproject.com/products/create)




// uncomment the following to enable URLs in path-format

		'urlManager'=>array(

			'urlFormat'=>'path',

                        'showScriptName'=>false,

                        'caseSensitive'=>false, 

			'rules'=>array(

				'<controller:\w+>/<id:\d+>'=>'<controller>/view',

				'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',

				'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',

			),

		),




This should help someone out!

I used the code from logos010 which was very close to working. I created this simple solution which worked for me.

In "myController" which extends "CController" I added this method:




	public function beforeAction()

	{

		Yii::app()->user->setReturnUrl(Yii::app()->request->getUrl());

		if (Yii::app()->user->isGuest && $this->id != "site")

			$this->redirect(Yii::app()->createUrl('site/login'));

	

		//optionally include code here if its an authenticated user

		return true;

	}



The differences from logos010’s code are

  • the “return true” at the end - this code doesn’t work if you leave that out,

  • checking for the current controller id to avoid an infinite loop on the redirect.

  • I also assume that the login (and other non-auth pages) are under "site" so this is changed too.

  • Stored the current Url into "returnUrl" so the user automagically comes back here after login

hi seenivasan

 your solution is working fine but i have one problem with that,

i m unable to get captcha image at login page.

do you have any solution for that plz inform me

I was facing the same problem wherein Captcha image was not getting displayed .

I solved the issue with following code (by checking that current request URL doesnt contain captcha word)

public function beforeAction()

    {


            Yii::app()-&gt;user-&gt;setReturnUrl(Yii::app()-&gt;request-&gt;getUrl());


            &#036;requestUrl=Yii::app()-&gt;request-&gt;url;


            if (Yii::app()-&gt;user-&gt;isGuest &amp;&amp; [color=&quot;#FF0000&quot;]( strpos(&#036;requestUrl, 'captcha') == null )[/color] )


                    &#036;this-&gt;redirect(Yii::app()-&gt;createUrl('site/login'));


    


            //optionally include code here if its an authenticated user


            return true;


    }

Hi Friends

The simplest way to achieve this stuff. Just add the below function in component/Controller.php

public function beforeAction(CAction $action)

{

	if(&#33;isset(Yii::app()-&gt;user-&gt;user_id) &amp;&amp;  &#33;(&#036;action-&gt;controller-&gt;id == 'site' &amp;&amp; &#036;action-&gt;id ==  'login'))


	{


	&#036;this-&gt;redirect(array('site/login')); 


	}

return true;

}

No need to add the beforeAction() in every controller.

Yii::app()->user->user_id

Here user_id can be any session variable.

use it in backend/config/main.php and frontend/config/main.php

after ‘components’ =>[],

 'as beforeRequest' =&gt; [


'class' =&gt; 'yii&#092;filters&#092;AccessControl',


'rules' =&gt; [


    [


        'actions' =&gt; ['login', 'error'],


        'allow' =&gt; true,


    ],


    [





        'allow' =&gt; true,


        'roles' =&gt; ['@'],


    ],


],

],

Hi,

I presume the above solutions will redirect all pages to login for a guest user? What if you have some pages that don’t require a login first? In that case would we need to put a check on each controller?

add this funtion in every controller.




public function beforeAction($action) {


if (Yii::app()->user->isGuest && Yii::app()->controller->action->id != "login") {

    Yii::app()->user->loginRequired();

}

//something code right here if user valid

return true;

        

}

site controller only needs Yii::app()->controller->action->id != "login" this condition. remove it for another controllers

How the work of the powers of users in yii1

my friends

If you allow

Me multiple users each user has specific powers

Is there a way to do it

By User Type

Types of user = 1,2,3,4

in yii1

I do not feel the With the use of I would like to gradually learn to do. Soon I would be a professional like you.

I do not feel the With the use of I would like to gradually learn to do. Soon I would be a professional like you. :lol: