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
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.