Authentication with rdSimpleAuthComponent

This component should make authentication very easy. The component utilizes the startup() callback so you do not need a beforeFilter. All you should need to do is put the component below in /app/controllers/components. Then make your controller or AppController.

AppController


filename: /app/app_controller.php
<?php
uses('sanitize');//include the sanitize lib
class AppController extends Controller {
 
    var $components = array('rdSimpleAuth');
    
    //OPTION 1: protect every page except the loginPage
    var $rdAccess = '*'; 
    
    //OR
    //OPTION 2: an array of actions. 
    var $rdAccess = array('admin_index' => array('Admin','Manager'),
                          'admin_add'   => array('Admin','Manager')
                         );
 
    var $Sanitize;
    function __construct()
    {
	parent::__construct();
	$this->Sanitize = &new Sanitize;
    }    
 
}
?>

You can override the settings in your AppController by setting var $rdAccess in each individual controller.

Database Setup

CREATE TABLE `users` (
  `id` int(10) NOT NULL auto_increment,
  `username` varchar(250) NOT NULL default '',
  `password` varchar(32) NOT NULL default '',
  `role` varchar(50) NOT NULL default 'User',
  `name` varchar(255) default NULL,
  `email` varchar(250) NOT NULL default '',
  `created` datetime NOT NULL default '0000-00-00 00:00:00',
  `modified` datetime NOT NULL default '0000-00-00 00:00:00',
  PRIMARY KEY  (`id`)
);

Login Method

here is the UsersController::login() method as an example of how to set the session.

<?php 
class UsersController extends AppController {
  
        function login()
	{		
		//RENDER VIEW IF USER IS LOGGED IN
		if($this->rdSimpleAuth->valid)
		{
			$this->redirect('/users/view');
		}
		//RENDER LOGIN FORM AND THEN HANDLE POST
		if (empty($this->data))
		{
			$this->render('login');
		}
		else
		{			
			$this->Sanitize->cleanArray($this->data);
			
			if ($this->User->validates($this->data))
			{
				$this->data['User']['username'] = $this->Sanitize->paranoid($this->data['User']['username'],array('.','_','-'));
				$this->data['User']['password'] = md5($this->data['User']['password']);
				
				$this->data = $this->User->find(array('User.username'=>$this->data['User']['username'], 'User.password'=>$this->data['User']['password']));
				
				if (is_numeric($this->data['User']['id']))
				{                   					
					//sets up the session vars
					$this->rdSimpleAuth->set($this->data['User']);
                                        /* This was causing problems when 'redirect' was set to something else.
                                         * Don't read it from session, instead use the variable from the component.
                                         * @author Mandy
                                         */
					//$this->redirect( $this->Session->read('rdAuth.redirect') );
                                        $this->redirect($this->rdSimpleAuth->loginPage);
				}
				else
				{
					$this->data['User']['password'] = '';
					$this->set('message', 'Invalid login/password');
				}
			}
			else
			{
				$this->data['User']['password'] = '';
				$this->set('message', 'Invalid login/password');
				$this->validateErrors($this->User);
			}
		}
	}  
 
}
 

Usage

Ok in your controllers you have $this→rdSimpleAuth available. lets say you want to check if the user is a member of the admins array. $this→rdSimpleAuth→admin should equal 1;

in the view you can use $this→controller→rdSimpleAuth→admin

Something a little trickier is to check if someone has the permissions to do some. Lets say we have the roles, Admin, Manager, User, Anon. Our allows array might look like $this→rdSimpleAuth→allows = array(’Admin⇒‘Admin’,’Manager’⇒‘Manager’,’User’⇒‘User’); we can put this in the beforeFilter or just add it directly to the component for each app. we can use the perms() method to check.

if($this->rdAuth->perms('User')) {
   //every role before User will have permission
   //so Admin, Manager, and User would all pass
}
using the roles to in the add form

in the controller we put $this→set(’roles’, $this→rdSimpleAuth→roles);

now in the view we can use <?php echo $html→selectTag(’User/role’, $roles, $html→tagValue(’User/role’), null, null, false);?>

this is what we might want to give to admin user, but if its someone its a regular registration form we just want to set the role by default. In this case we do: $this→data[’User’][’role’] = end($this→rdAuth→roles);

rdSimpleAuthComponent

filename: /app/controllers/components/rd_simple_auth.php

 
<?php
/*
 * rdSimpleAuth Component
 *
 * @author		gwoo <gwoo@rd11.com>
 * @version		1.1.4.3104
 * @license		MIT
 *
 */
class rdSimpleAuthComponent extends Object
{
	var $components = array('Session');
	/**
	* the redirect if auth fails.
	*
	* @var string
	* @access public
	*/
	var $loginPage = '/users/login';
	
	/**
	* all roles available
	*
	* @var array
	* @access public
	*/
	var $roles = array('Admin'=>'Admin');
	
	/**
	* if role assigned to the logged in user matches admins array
	*
	* @var array
	* @access public
	*/
	var $admins = array('Admin'=>'Admin'); 
	
	/**
	* allowed roles 
	*
	* @var array
	* @access public
	*/
	var $allows = array('Admin'=>'Admin');
	
	/**
	* id of the logged in user
	*
	* @var unknown_type
	* @access private
	*/             
	
	var $id = null;
	
	/**
	* username of the logged in user
	*
	* @var string
	* @access private
	*/
	var $username = null;
	
	/**
	* role assigned to the logged in user
	*
	* @var string
	* @access private
	*/
	var $role = null;
 
	/**
	* if admins passes then set admin var
	*
	* @var bool
	* @access private
	*/
	var $admin = null;  
	
	/**
	* if role passes users set allowed
	*
	* @var boolean
	* @access private
	*/
	var $allow = null;
		
	/**
	* Valid if role, username , and id exist.
	*
	* @var string
	* @access public
	*/
	var $valid = false;  
	
	/**
	* Error messages to be displayed if the user is short of access for the requested action.
	*
	* @var string
	* @access private
	*/
	var $errors = null;
	
	/**
	* Uses callback to automatically check rights
	* @return redirect if check fails
	*/
	function startup(&$controller)
	{	 
		$this->set();              
		
		if(!isset($controller->params['url']['url'])) {
			$controller->params = array('url'=>array('url'=>''));
		}       
		$vars = get_class_vars($controller->name.'Controller'); 
	
		if(empty($vars['rdAccess'])) {
			$vars = get_class_vars('AppController');
		} 
		
		if(!empty($vars['rdAccess']) && !strstr($controller->params['url']['url'], substr($this->loginPage, 1)))
		{                                           		
			if($this->check($controller->action, $vars['rdAccess']) == false) 
			{              
		    	$this->Session->write('rdAuth.redirect', $controller->params['url']['url']);
		  		$controller->redirect($this->loginPage);
		  		exit;
			}
			else
			{
				if($this->Session->check('rdAuth.redirect'))
				{    
					$redirect  = $this->Session->read('rdAuth.redirect');
				    $this->Session->del('rdAuth.redirect');
					$controller->redirect($redirect); 
			    	
				}
			}
		}
	}
	
	/**
	* Function to check the session and return local vars
	*
	* @param string $data used for login method
	* @return errors
	*/
	function set($data='')
	{
		if($data)
		{
			$this->Session->write('rdAuth.id', $data['id']);
			$this->Session->write('rdAuth.username', $data['username']);
			$this->Session->write('rdAuth.role', $data['role']);
		}
		if($this->Session->check('rdAuth') && $this->Session->valid('rdAuth'))
		{
			$this->id = $this->Session->read('rdAuth.id');
			$this->username = $this->Session->read('rdAuth.username');
			$this->role = $this->Session->read('rdAuth.role');
			if(in_array($this->role,$this->admins))
			{
				$this->admin = 1;	
			}
			if(in_array($this->role,$this->allows))
			{
				$this->allow = 1; 
			}
			if($this->id && $this->username && $this->role)
			{
				$this->valid = 1;
			}
		}
		elseif($this->Session->error())
		{
			return $this->Session->error();
		}
	}
	
	/**
	* logout method deletes session
	*
	* @return errors
	*/
	function logout()
	{
		$this->Session->del('rdAuth.id');
		$this->Session->del('rdAuth.username');
		$this->Session->del('rdAuth.role');
		$this->Session->del('rdAuth');
		if($this->Session->error())
		{
			return $this->Session->error();
		}
	}  
   	
	/**
	* Function to check the access for the action based on the access list
	*
	* @param string $action The action for which we need to check the access
	* @param array $access Access array for the controller's actions
	* @return boolean
	*/
	function check($action, $access = '')
	{	 
		if($access == '*')
		{   
	    	if($this->valid && $this->allow)
			{   
				return true;
			}               
			return false;
		} 
		else
		if (is_array($access) && array_key_exists($action, $access))
		{
			if($this->role)
			{	
				if (in_array($this->role, $access[$action]))
				{
					return true;
				}
				else
				{
					return false; 
				}
			}
			else
			if($this->id)
			{	
				if (in_array($this->id, $access[$action]))
				{
					return true;
				}
				else
				{
					return false; 
				}
			} 
			else
			if($this->username)
			{	
				if (in_array($this->username, $access[$action]))
				{
					return true;
				}
				else
				{
					return false; 
				}
			}
			else 
			{
				return false; 
			}
		}
		return	true;
	}
	
	/**
	* Function to check if a access is authorized on a row in the database
	* your table would have a field that contains the role just like the user table                                                                     
	*
	* @param string $item The field for which we need to check the access
	* @return boolean
	*/
	function perm($item = null)
	{
		if (isset($item) && isset($this->role))
		{
			if(in_array($this->role,$this->allows))
			{
				$flipped = array_flip(array_values($this->allows)); 
				if(isset($flipped[$item]) && $flipped[$item] >= $flipped[$this->role])
				{
					return true;
				}
			}			
		}
		return false;
	}
}
?>
 
tutorials/authentication_with_rdsimpleauth.txt · Last modified: 2006/09/06 13:04 by j_king