2
votes

I'm new on the Cakephp, and im trying to get around with it. Im building a simple authentication system (login/logout). Im using Cakephp build-in AuthCommponent for that.

Tables:

USERS: id|name|surname|username|password|role

role=admin/client.

I have build the login and logout script and works perfect. The logic i want to achieve is this:

One user (client) can view/edit/delete only himself. admin can edit/view/delete everyone.

So i have build/

app/Controller/AppController

    <?php
    App::uses('Controller', 'Controller');
    class AppController extends Controller {
        public $helpers = array(
            'Html', 
            'Form',
            'Session',
            'Js'
        );
        public $components = array(
            'DebugKit.Toolbar',
            'Acl',
            'Cookie',
            'Session',
            'Security', 
            'Auth' => array(
                'loginAction' => array('controller' => 'users', 'action' => 'login'),
                'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
                'logoutRedirect' => array('controller' => 'users', 'action' => 'login'),
                'authError' => 'Youd dont have permission for that action.',
                'loginError' => 'Invalid Username or Password entered, please try again.',
                'authorize'=>array('Controller'),
            )
        );



        /*****************************************************
        *               AUTHORIZATION
        ******************************************************/
        public function isAuthorized($user = null) {        
            if (isset($user['role']) && ($user['role'] === 'admin')) 
            {       
                return true;
            }   
            //default deny
            return false;
        }

        /*****************************************************
        *               BEFORE FILTER FUNCTION
        ******************************************************/
        public function beforeFilter() {
            parent::beforeFilter();
            $this->Auth->allow('display');
            $this->set('logged_in', $this->Auth->loggedIn()); 
            $this->set('current_user', $this->Auth->user());

            if (!$this->Auth->loggedIn()) {
                $this->Auth->authError = "You must be logged in to view this page!";
            }

        }

    } 
?>

User model is as follow:

app/Model/User

<?php
App::uses('AppModel', 'Model');
class User extends AppModel {

/**
 * Display field
 *
 * @var string
 */
    public $displayField = 'name';

/**
 * Validation rules
 *
 * @var array
 */
    public $validate = array(

        'id' => array(
            'blank' => array(
                'rule' => 'blank',
                'on' => 'create',
            ),
        ),
        'name' => array(
            'maxLength' => array(
                'rule' => array('maxLength', 50),
                'message' => 'Il nome utente non può superare i 50 caratteri.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Il nome utente non può essere vuoto.',
                'allowEmpty' => false
            ),
        ),
        'surname' => array(
            'maxLength' => array(
                'rule' => array('maxLength', 50),
                'message' => 'Il nome utente non può superare i 50 caratteri.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Il nome utente non può essere vuoto.',
                'allowEmpty' => false
            ),
        ),
        'username' => array(
            'maxLength' => array(
                'rule' => array('maxLength' , 50),
                'message' => 'Username non può superare i 50 caratteri.',
            ),
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Username non può essere vuoto.',
                'allowEmpty' => false
            ),
            'isUnique' => array(
                'rule' => 'isUnique',
                'message' => 'Questo utente già esiste.',
            ),
        ),
        'password' => array(
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Password can\'t be empty',
            ),
            'minLength' => array(
                'rule' => array('minLength',5),
                'message' => 'Password should be more then 5 characters long',
            ),
           'matchPasswords'=>array(
                'rule'=>'matchPasswords',
                'message'=>'La password non corrisponde!'
            ),
        ),
        'confirm_password'=>array(
            'notEmpty'=>array(
                'rule'=> array('notEmpty'),
                'message'=>'Confermare la password.'
            ),
         ),
        'role' => array(
            'notEmpty' => array(
                'rule' => array('notEmpty'),
                'message' => 'Non deve essere vuoto.',
            ),
            'words' => array(
                'rule' => array('custom', '/[0-9A-Za-z\._-]/'),
                'message' => 'Username può contenere solo lettere, numeri e spazi.',
            ),          
            'valid' => array(
                'rule' => array('inList', array('admin', 'client')),
                'message' => 'Inserire un valido ruolo!',
                'allowEmpty' => false,
            ),
        ),
    );
/*****************************************************
* CHECK IF USER TYPES CORRECT THE PASSWORD - REGISTER
******************************************************/
    public function matchPasswords($data) {
        if ($data['password'] == $this->data['User']['confirm_password']) {
            return true;
        }
        $this->invalidate('confirm_password', 'La password non corrisponde!');
        return false;
    }       
/*****************************************************
*       BEFORE SAVE
******************************************************/
    // this is a Global variablke that im gonna use it inside my function
    public function beforeSave($options = array()) {
        // Adding new user
        if (isset($this->data[$this->alias]['password'])) { 
            //[$this->alias] is instead of ['User']
           $this->data[$this->alias]['password'] = AuthComponent::password($this->data[$this->alias]['password']);
        }   
        return true;
    }
}
?>

And the UserController :

app/Controller/UsersController

<?php
App::uses('AppController', 'Controller');
class UsersController extends AppController {


public $uses = array('User');
public $helpers = array('Html', 'Form');
public $components = array('Paginator');

/**
 * beforeFilter method
  * @return void
 */
    public function beforeFilter() {
        parent::beforeFilter();         
        $this->Auth->allow('add','login','logout');
        $this->Auth->autoRedirect = false;  
    } 

/**
 * user authorization method
 * @return void
 */ 
    public function isAuthorized($user = null) {
        if ($this->action === 'index') {
            return true;
        }
        // All registered users can add posts
        if ($this->action === 'add') {
            return true;
        }
        // The owner of a post can edit and delete it
        if (in_array($this->action, array('view','edit', 'delete'))) {
            // debug($this->request->params['pass']);
            $user_id =(int)$this->request->params['pass'][0];
            $logged_in_user = (int)$user['id'];
            if ($user_id === $logged_in_user) {
                return true;
            }
        }
        return parent::isAuthorized($user);
    }


/**
 * login method
  * @return void
 */
    public function login() {
        if ($this->Session->read('Auth.User')) {
            $this->Session->setFlash('You are allredy logged in!');
            return $this->redirect($this->Auth->redirectUrl());
        }

        if ($this->request->is('post')) {
            if ($this->Auth->login()) {
                $this->Session->setFlash(__('You Have Been Logged in.'));
                return $this->redirect($this->Auth->redirectUrl());
            } else { 
                $this->Session->setFlash(__('Invalid username/email - Password Combination.')); 
            }
        }
    }


/**
 * logout method
  * @return void
 */
    public function logout() {
         $this->Auth->logout();
         $this->redirect($this->Auth->redirectUrl());
    }   

/**
 * index method
  * @return void
 */
    public function index() {
        $this->User->recursive = 0;
        $this->set('users', $this->Paginator->paginate());
    }

/**
 * view method
  * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function view($id = null) {
        // debug($this->params['action']);
        if (!$this->User->exists($id)) {
            throw new NotFoundException(__('Invalid user'));
        }
        $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
        $this->set('user', $this->User->find('first', $options));
    }

/**
 * add method
  * @return void
 */
    public function add() {
        if ($this->Session->read('Auth.User')) {
            $this->Session->setFlash('You are allredy Have an Account!');
            return $this->redirect($this->Auth->redirectUrl());
        }
        if ($this->request->is('post')) {
            $this->User->create();
            if ($this->User->validates()) {
                if ($this->User->save($this->request->data)) {
                    $this->Session->setFlash(__('The user has been saved.'));
                    return $this->redirect(array('action' => 'index'));

                } else {
                    $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
                }
            }
        }
    }


/**
 * edit method
  * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function edit($id = null) {
        if (!$this->User->exists($id)) {
            throw new NotFoundException(__('Invalid user'));
        }
        if ($this->request->is(array('post', 'put'))) {     
            if ($this->User->save($this->request->data)) {
                $this->Session->setFlash(__('The user has been saved.'));
                return $this->redirect(array('action' => 'index'));
            } else {
                $this->Session->setFlash(__('The user could not be saved. Please, try again.'));
            }
        } else {
            $options = array('conditions' => array('User.' . $this->User->primaryKey => $id));
            $this->request->data = $this->User->find('first', $options);
        }
    }

/**
 * delete method
  * @throws NotFoundException
 * @param string $id
 * @return void
 */
    public function delete($id = null) {
        $this->User->id = $id;
        if (!$this->User->exists()) {
            throw new NotFoundException(__('Invalid user'));
        }
        $this->request->allowMethod('post', 'delete');
        if ($this->User->delete()) {
            $this->Session->setFlash(__('The user has been deleted.'));
        } else {
            $this->Session->setFlash(__('The user could not be deleted. Please, try again.'));
        }
        return $this->redirect(array('action' => 'index'));
    }
}
?>

=> I have two users registered. 1) admin, 2) client.

a) when i login as admin , works OK, b) when i login as client and try to view/edit/delete myself works perfect, but when i try to edit another user, it deny the action (as it suppose to), but when it redirect it doesn't redirect to index page but to application root folder and generates and error.

i have a folder named cakeaproject where my application lyes.

http://localhost/cakeaproject/users/ 

and the authError Redirects to:

http://localhost/cakeaproject/cakeaproject/users/ 

Missing Controller

Error:  CakeappprojectsController could not be found.

Error:  Create the class  CakeaprojectController below in file: app\Controller\ CakeaprojectController.php
<?php
class  CakeaprojectController extends AppController {

}

And my routing.php file is as follow:

app/Config/routes.php

    Router::connect('/', array('controller' => 'users', 'action' => 'index','home'));
    Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
    Router::connect('/register', array('controller' => 'users', 'action' => 'add'));

    Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
    CakePlugin::routes();
    require CAKE . 'Config' . DS . 'routes.php';
?>

And the best part is that on Moxilla/Safari(for desktop)/Tourch works OK and on Chrome/SeaMonkey/IE has the problem.

2

2 Answers

1
votes

I would place it inside your Users controller in an afterRender(); filter such as :

so in:

app/Controller/UsersController.php

public function beforeRender() {
    parent::beforeRender(); 
    $this->Auth->unauthorizedRedirect = array('controller'=>'users','action'=>'index');
}
0
votes

For edit your unauthorizeRedirect please see : http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#AuthComponent::$unauthorizedRedirect

SO in your controller

'Auth' => array(
                'loginAction' => array('controller' => 'users', 'action' => 'login'),
                'loginRedirect' => array('controller' => 'users', 'action' => 'index'),
                'logoutRedirect' => array('controller' => 'users', 'action' => 'login'),
                'authError' => 'Youd dont have permission for that action.',
                'loginError' => 'Invalid Username or Password entered, please try again.',
                'authorize'=>array('Controller'),.
                'unauthorizedRedirect'=>array('controller'=>'yours','action'=>'...')

            )