We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Log out (with method post)

Log out (with post method)

How to logout from site using post method?

I tried to logout from system but phalcon says token is invalid.

Seems the csrf-token is different between the partials in the same generated page.

Actions work fine.

This is my code:

app/config/routes.php

<?php

$di->set('router', function() {
    $router = new Router(false);
    $router->removeExtraSlashes(true);

    $router->addGet('/', array(
       'controller' => 'index',
       'action' => 'index'
    ));

    // more routes...

    $router->addGet('/admin/index', array(
       'controller' => 'admin',
       'action' => 'index'
    ));

    $router->addPost('/admin/post1', array(
       'controller' => 'admin',
       'action' => 'post1'
    ));

    $router->addPost('/admin/post2', array(
       'controller' => 'admin',
       'action' => 'post2'
    ));

    $router->add('/admin/login', array(
       'controller' => 'admin',
       'action' => 'login'
    ))->via(['GET', 'POST']);

    $router->addPost('admin/logout', array(
       'controller' => 'admin',
       'action' => 'logout'
    ));

    return $router;
});

app/controllers/AdminController.php

<?php

namespace App\Controllers;

use Phalcon\Http\Response as Response;
// use App\Libraries\Auth\Exception as AuthException;

class AdminController extends ControllerBase
{
    public function indexAction()
    {
        return $this->view->render('admin', 'index');
    }

    public function post1Action()
    {
        if ($this->request->isPost()) {
            if ($this->security->checkToken() == false) {
                $this->flash->error('Invalid token in post1, try again');
                return $this->response->redirect('admin/index');
            }

            $this->flash->success('post1 is fine');
            return $this->response->redirect('admin/index');
        }
    }

    public function post2Action()
    {
        if ($this->request->isPost()) {
            if ($this->security->checkToken() == false) {
                $this->flash->error('Invalid token in post2, try again');
                return $this->response->redirect('admin/index');
            }

            $this->flash->success('post2 is fine');
            return $this->response->redirect('admin/index');
        }
    }

    public function loginAction()
    {
        // login logic...
    }

    public function logoutAction()
    {
        if ($this->request->isPost()) {
            if ($this->security->checkToken() == false) {
                $this->flash->error('Invalid token in logout, try again');
                return $this->response->redirect('admin/index');
            }

            // $this->administrators_auth->remove();
            $this->flash->success('Finished session');
            return $this->response->redirect('index');
        }
    }
}

app/views/main.volt.php

{# main template #}
<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="utf-8">
    <title>APPNAME</title>
  </head>
  <body>
    <div id="page">
      <!-- header -->
      {{ partial('partials/menu_admin') }}
      <!-- end header -->

      <!-- content -->
      {% block content %}{% endblock %}
      <!-- end content -->

      <!-- footer -->
      {# { partial('partials/footer') } #}
      <!-- end footer -->
    </div>
  </body>
</html>

app/views/partials/menu_admin.volt.php

{# partial menu_admin #}
<div class="top-menu">
  <div class="container">
    <div class="row">
      <div class="col-xs-2">
        <div id="colorlib-logo">
          <a href="#">APPNAME</a>
        </div>
      </div>
      <div class="col-xs-10 text-right menu-1">
        <ul class="dropdown">
          <li><a href="#">Profile</a></li>
          <!-- logout through get method, working...
          <li><a href="{# { url('admin/logout') } #}">Salir</a></li>
          -->
          <!-- logout through post method, not working... -->
          <li>
            <a href="{{ url('admin/logout') }}"
              onclick="event.preventDefault();
              document.getElementById('logout-form').submit();">
              Salir
            </a>
          </li>
          <form id="logout-form" action="{{ url('admin/logout') }}" method="post" style="display: none;">
            <input type="hidden" name="{{ security.getTokenKey() }}" value="{{ security.getToken() }}">
          </form>  
        </ul>
      </div>
    </div>
  </div>
</div>

app/view/admin/actions.volt.php

{# partial actions #}

{% extends 'main.volt.php' %}

{% block title %}ACTIONS{% endblock %}

{% block content %}
<div class="container">
  <div class="row">
    <div class="col-md-12">
      {% for msg in flashSession.getMessages('success') %}
        <div class="alert alert-success alert-dismissible fade in" role="alert">
          <strong>Ok</strong>
          <li>{{ msg }}</li>
        </div>
      {% endfor %}

      {% set output = flash.getMessages('error') %}
      {% if output | length %}
        <div class="alert alert-danger alert-dismissible fade in" role="alert">
          <strong>Error</strong> 
          {% for msg in output %}
            <li>{{ msg }}</li>
          {% endfor %}
        </div>
      {% endif %}

      {% for msg in flashSession.getMessages('warning') %}
        <div class="alert alert-warning alert-dismissible fade in" role="alert">
          <strong>Important</strong>
          <li>{{ msg }}</li>
        </div>
      {% endfor %}
    </div>
  </div>
  <div class="row">
    <h2>
      <strong>Options</strong>
    </h2>
    {{ form('admin/post1/', 'method': 'post') }}
      <input type="hidden" name="{{ security.getTokenKey() }}" value="{{ security.getToken() }}">
      <button type="submit" title="Update" class="btn-options btn-danger btn-xs">
        Update
      </button>
    {{ end_form() }}

    {{ form('admin/post2/', 'method': 'post') }}
      <input type="hidden" name="{{ security.getTokenKey() }}" value="{{ security.getToken() }}">
      <button type="submit" title="Delete" class="btn-options btn-danger btn-xs">
        Delete
      </button>
    {{ end_form() }}
  </div>
</div>
{% endblock %}

What's wrong?

Thank you.



77.7k
Accepted
answer

I dont think fields under display: none will get submitted with the post request. Try to set the form to visibility: hidden

Are you calling security.getTokenKey() and security.getToken() multiple times for a single page load? I believe each of invocation of those methods generates a new value. So if you call security.getToken() twice, the first form won't have a valid token because it will have been re-generated for the second form.

What you can do is retrieve it only once per page load. You can do that by assigning the token and key in:

  • In ControllerBase, create a beforeExecuteRoute() method, and assign the token & key to the view, or
  • Do the same thing in the service definition for your "view".

Thanks to all!