Wednesday, April 14, 2010

LoginRequired and Ajax Updates

My Issue:
If my user session times out while an access restricted page is visible (say I left it open overnight), and the user then clicks on a button that performs an ajax call, the login required display appears within the div that the ajax update should happen in, rather than replacing the entire current page.

Potential Solutions:
Option 1) Extend the CWebUser and override the loginRequired() function to check for $request->isAjaxRequest (this would then need to redirect to a page which causes a javascript redirect)

Option 2) Modify the Site actionLogin to check the request type and render a different page which causes a javascript redirect.

Option 2 is the least invasive method, so I am going to go with that option and see how things work out ;)

Site Note: Could override the controller->redirect method, but I don't want to necessarily block all redirects -- I can forsee needing to have one ajax view action redirect to another ajax view action. If the controller override was used, it would have to be done on every controller - hardly efficient.


To begin, I open up the SiteController.php and modify the actionLogin method as follows:

public funciton actionLogin()
{
    $model = new LoginForm;
    if (isset($_POST['ajax'] && $_POST['ajax'] ==='login-form')
    {
      // ... standard stuff here
    } 
   
    if ( $request = Yii::app()->getRequest() && $request->isAjaxRequest)
    {
       // ensure we're rendering this in a parent window, not an update div
       $this->renderPartial('loginRedirect', array(), false, true);
       Yii::app()->end();
    }
    ... //original code continues
}

Then the new views/site/ folder - loginRedirect.php
<script>
  window.location = '<?php echo $this->createAbsoluteUrl('site/login')?>';
</script> 



EDIT:

Going back to option 1:

Extend CWebUser (Saved into /protected/components/WebUser.php)
class WebUser extends CWebUser
{
    public function loginRequired()
    {
       $app = Yii::app();
       $request = $app->getRequest();
       $this->setReturnUrl( $request->getUrl());
       if (($url = $this->loginUrl)!== null)
       {
           if (is_array($url))
           { 
             ... nothing here changes
           }
           if ( $request->isAjaxRequest )
           {
             // this is nasty -- just for test. Change this to a renderPartial w/ the redirect script.
             echo "You must be logged in to perform this action";
           } 
           else
           {
               $request->redirect($url);
           }
       }
    }
}

and in the main/config.php
   'components'=>array(
    'user'=>array(
        'class'=>'WebUser',
        ...
     ),
    ...