Home > OS >  Error: The action you requested is not allowed. My API is blocked by filters when the HTTP request m
Error: The action you requested is not allowed. My API is blocked by filters when the HTTP request m

Time:03-22

I am building a Web App along with API for Android using CI4.

For the Web App, I have a filter to check whether the user already logged in with some exceptions, one of them is to ignore the filter if the URL consists api/* (The url for API is http://localip/api/)

The API is working fine if the request method is GET. I can get the data from API. But when I tried to insert a data to database using POST method, it redirects me to login page (I'm using Postman to test the API)

How do I fix this?

What I have tried so far was adding login filter alias to

public $methods = [
        'post' => ['csrf', 'loginfilter']
    ]; But still not working

Here is the full code

Filters.php

<?php

namespace Config;

use App\Filters\CorsFilter;
use App\Filters\LoginFilter;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Filters\CSRF;
use CodeIgniter\Filters\DebugToolbar;
use CodeIgniter\Filters\Honeypot;
use CodeIgniter\Filters\InvalidChars;
use CodeIgniter\Filters\SecureHeaders;

class Filters extends BaseConfig
{
    /**
     * Configures aliases for Filter classes to
     * make reading things nicer and simpler.
     *
     * @var array
     */
    public $aliases = [
        'loginfilter' => LoginFilter::class,
        'cors' => CorsFilter::class
    ];

    /**
     * List of filter aliases that are always
     * applied before and after every request.
     *
     * @var array
     */
    public $globals = [
        'before' => [
            // 'honeypot',
            'csrf',
            'loginfilter' => ['except' => ['/', '/login', 'api/*']],
            'cors'
            // 'invalidchars',
        ],
        'after' => [
            'toolbar',
            // 'honeypot',
            // 'secureheaders',
        ],
    ];

    /**
     * List of filter aliases that works on a
     * particular HTTP method (GET, POST, etc.).
     *
     * Example:
     * 'post' => ['csrf', 'throttle']
     *
     * @var array
     */
    public $methods = [
        'post' => ['csrf','loginfilter]
    ];

    /**
     * List of filter aliases that should run on any
     * before or after URI patterns.
     *
     * Example:
     * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
     *
     * @var array
     */
    public $filters = [];
}

LoginFilter.php

<?php

namespace App\Filters;

use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;

class LoginFilter implements FilterInterface
{

    public function before(RequestInterface $request, $arguments = null)
    {
        $session = session();
        if (!$session->has('user_id')) {
            return redirect()->to(base_url() . '/');
        }
    }

    public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
    {
    }
}

Routes.php

$routes->resource("api/role", ['controller' => 'apis\MasterDataRoleApi']);

MasterDataRoleApi.php (Controller)

<?php

namespace App\Controllers\apis;

use App\Models\GeneralModels;
use App\Models\RoleModel;
use CodeIgniter\API\ResponseTrait;
use CodeIgniter\RESTful\ResourceController;

class MasterDataRoleApi extends ResourceController
{
    use ResponseTrait;
    protected $model;
    protected $generalModel;

    public function __construct()
    {
        $this->model = new RoleModel();
        $this->generalModel = new GeneralModels();
    }

    public function index()
    {
        $role= $this->request->getVar('role');
        $data = $this->model->getRoleApi($role);
        return $this->respond($data, 200);
    }

    public function create()
    {
        $roleName = $this->request->getPost('role_name');
        $supervisor = $this->request->getPost('supervisor');
        $userId = $this->request->getVar("userId");
        helper('idgenerator');
        $maxCode = $this->generalModel->getMaxData('tmrole', 'role_id');
        $generatedId = idGenerator($maxCode[0]['role_id'], 4, 3, "JAB-");

        $this->model->insertTmRole($generatedId, $roleName, $userId, $userId);
       

        $data = array();

        $dataArr = array(
            "response" => "Success",
            "response_details" => "Saved Successfully"
        );

        $data[] =  $dataArr;

        return $this->respondCreated($data, 201);
    }
}

Image below shows Json returned when request method is GET enter image description here

The X-CSRF-TOKEN HTTP request header value should be the same as the csrf_cookie_name cookie value.

HTTP Request Call Requirements:

I.e:

POST http://myapp.local/api/companies

Request Body. Don't forget to add the csrf_cookie_name token as part of the request body.

Key Value
company_name Tesla, Inc.
csrf_cookie_name 62b04a891414ef789bee7108f94ad97a

As I conclude with PART B:

Important items Description
ci_session cookie or an Authorization: Bearer xxxxxxx HTTP request header. Allows you to authenticate with your application/project only for Auth protected API endpoints. In your particular case, I believe your loginfilter is working with a ci_session cookie and the cookie is expected to be sent along with every request with the help of the Cookie HTTP request header.
csrf_cookie_name cookie and (a X-CSRF-TOKEN HTTP request header or CSRF token request parameter). The CSRF cookie and (X-CSRF-TOKEN HTTP request header or CSRF token request parameter) values MUST match. This is a requirement if you've turned on the csrf filter.

CodePudding user response:

From what I can see is, you have loginfilter as a fallback for every POST method. That might be the culprit over there.

That being said, here is an alternate solution. You could group the routes in routes.php and apply loginfilter to those routes. Additionally you can nest them and partition them as you want.

Example :

$routes->group(
    'api',
    ['filter' => 'loginfilter'],
    function ($routes) {
        $routes->resource("role", ['controller' => 'apis\MasterDataRoleApi']);
    }
);

You can remove the global filters while using this method.

  • Related