Truong Van Hoc
Truong Van Hoc

Reputation: 87

Flash message shows twice in a view CakePHP3

I've encountered this issue several times and tried to avoid it by removing calling Flash method. Lately, I want to show an error flash to non-logged in user who tries to log out. However, when I test this action(by accessing localhost:8765/users/logout without being logged in), everything works fine except I get 2 error messages "You are not authorized to access this location". How can I fix this issue?

Here are my codes

In AppController:

public function initialize()
{
    parent::initialize();

    $this->loadComponent('RequestHandler');
    $this->loadComponent('Flash');
    $this->loadComponent('Auth', [
        'authorize' => ['Controller'],  //For User authorize checking, this tells app to let each controller decides own rules for authorize
       'loginRedirect' => ['controller' => 'Articles', 'action' => 'index'],
       'logoutRedirect' => ['controller' => 'Users', 'action' => 'index']
    ]);
}

public function beforeFilter(Event $event)
{
    //this applied to every controller
    $this->Auth->allow(['index', 'view', 'display']);
}

  ...

public function isAuthorized($user)
{
    //Admin can access every action
    if(isset($user['role']) && $user['role'] === 'admin'){
        return true;
    }

    //Default deny
    return false;
}

In UsersController:

public function isAuthorized($user)
{
    //All registered users can add articles
    if($this->request->action === 'add'){
        return true;
    }

    //The self user can edit and delete the account
    if(in_array($this->request->action, ['edit', 'delete'])){            
        //get id of targeted user
        $targetUserId = (int)$this->request->params['pass'][0];
        //check if current user is the targeted user
        if($this->Users->selfUser($targetUserId, $user['id'])){
            return true;
        }else{
            $this->Flash->error(__('You are not authorized for this action'));
        }
    }
    return parent::isAuthorized($user);
}

public function beforeFilter(Event $event)
{
    parent::beforeFilter($event);
    $this->Auth->allow(['add']);
}

...

public function logout()
{
    return $this->redirect($this->Auth->logout());
}

In UsersTable

public function selfUser($targetedUserId, $userId)
{

    return $targetedUserId == $userId;
}

In default.ctp

$cakeDescription = 'CakePHP: the rapid development php framework';
?>
<!DOCTYPE html>
<html>
<head>
    <?= $this->Html->charset() ?>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>
        <?= $cakeDescription ?>:
        <?= $this->fetch('title') ?>
    </title>
    <?= $this->Html->meta('icon') ?>

    <?= $this->Html->css('base.css') ?>
    <?= $this->Html->css('cake.css') ?>

    <?= $this->fetch('meta') ?>
    <?= $this->fetch('css') ?>
    <?= $this->fetch('script') ?>
</head>
<body>
    <nav class="top-bar expanded" data-topbar role="navigation">
        <ul class="title-area large-3 medium-4 columns">
            <li class="name">
                <h1><a href=""><?= $this->fetch('title') ?></a></h1>
            </li>
        </ul>
        <div class="top-bar-section">
            <ul class="right">
                <li><a target="_blank" href="http://book.cakephp.org/3.0/">Documentation</a></li>
                <li><a target="_blank" href="http://api.cakephp.org/3.0/">API</a></li>
            </ul>
        </div>
    </nav>
    <?= $this->Flash->render() ?>
    <div class="container clearfix">
        <?= $this->fetch('content') ?>
    </div>
    <footer>
    </footer>
</body>
</html>

In login.ctp

<div class="users form">
<?= $this->Flash->render('auth') ?>
<?= $this->Form->create() ?>
    <fieldset>
        <legend><?= __('Please enter your username and password') ?></legend>
        <?= $this->Form->input('username') ?>
        <?= $this->Form->input('password') ?>
    </fieldset>
<?= $this->Form->button(__('Login')); ?>
<?= $this->Form->end() ?>
</div>

Upvotes: 0

Views: 1288

Answers (2)

ELRECO
ELRECO

Reputation: 30

You must add this line in your logout action:

$this->autoRender = false;

So, in your case, your UsersController should be:

public function isAuthorized($user)
{
    //All registered users can add articles
    if($this->request->action === 'add'){
        return true;
    }

    //The self user can edit and delete the account
    if(in_array($this->request->action, ['edit', 'delete'])){            
        //get id of targeted user
        $targetUserId = (int)$this->request->params['pass'][0];
        //check if current user is the targeted user
        if($this->Users->selfUser($targetUserId, $user['id'])){
            return true;
        }else{
            $this->Flash->error(__('You are not authorized for this action'));
        }
    }
    return parent::isAuthorized($user);
}

public function beforeFilter(Event $event)
{
    parent::beforeFilter($event);
    $this->Auth->allow(['add']);
}

...

public function logout()
{
    $this->autoRender = false;
    return $this->redirect($this->Auth->logout());
}

Upvotes: 0

Dreamweaver
Dreamweaver

Reputation: 53

Could you also post even just an excerpt from your CTP file? It could be possible that within the page layout the Flash was rendered twice.

Upvotes: 1

Related Questions