AppController Class is not working on Sub directory Cakephp 3 - cakephp

I am creating a REST Api using cakephp-jwt-auth But the AppController I create in subfolder is not called.
My App controller code inside Ca/Api code
<?php
namespace App\Controller\Ca\Api;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email'],
],
'ADmad/JwtAuth.Jwt' => [
'parameter' => 'token',
'userModel' => 'Users',
'fields' => [
'username' => 'id'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize'
]);
$this->loadComponent('BryanCrowe/ApiPagination.ApiPagination', [
'key' => 'paging',
'aliases' => [
'page' => 'currentPage',
'current' => 'resultCount'
],
'visible' => [
'currentPage',
'resultCount',
'prevPage',
'nextPage',
'pageCount',
'page',
]
]);
}
public function beforeFilter(Event $event) {
parent::beforeFilter($event);
}
}
And my route file:
Router::prefix('ca/api', function ($routes) {
$routes->setExtensions(['json']);
$routes->connect('/login', ['controller' => 'Login', 'action' => 'login', "prefix" => "ca/api"]);
$routes->connect('/dashboard', ['controller' => 'Dashboard', 'action' => 'home', 'prefix' => "ca/api"]);
$routes->fallbacks('InflectedRoute');
});
My app controller class is not called and I don't understand where I am doing wrong.

you can create controller like this
<?php
namespace App\Controller\Api;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Auth', [
'storage' => 'Memory',
'authenticate' => [
'Form' => [
'scope' => ['Users.group_id' => 1]
],
'ADmad/JwtAuth.Jwt' => [
'parameter' => 'token',
'userModel' => 'Users',
'fields' => [
'username' => 'id'
],
'queryDatasource' => true
]
],
'unauthorizedRedirect' => false,
'checkAuthIn' => 'Controller.initialize'
]);
}
}
And other controller like this
<?php
namespace App\Controller\Ca;
use Cake\Event\Event;
use Cake\Http\Exception\UnauthorizedException;
use Cake\Utility\Security;
use Firebase\JWT\JWT;
use Cake\Http\ServerRequest;
use Cake\I18n\Time;
use Aws\S3\S3Client;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\Filesystem;
use Cake\Http\Exception\NotFoundException;
class DashboardController extends AppController
{
public function initialize()
{
parent::initialize();
}
public function home()
{
pr("hiiih");
}
}
Remember do not use
**
use App\Controller\AppController;
**
When you are creating AppController in sub folder
for more information read this tutorial :- https://trinitytuts.com/secure-cakephp-web-services-using-jwt/

The AppController isn't called magically someplace internally in CakePHP. The Routes you define call a specific controller, which should simply extend your AppController.
Following convention you'd typically only ever use a single AppController for your entire application, in /src/Controller/AppController. It looks based on the authentication methods listed in your example, this is the approach your taking, but you don't need to move it into a subfolder to make prefix routing work.
Based on your routes:
Router::prefix('ca/api', function ($routes) {
... This will look for a classes that match connections inside /src/Controller/Ca/Api, and for matches like:
// Note, the "prefix" item you listed on this line is not required I'd remove it:
$routes->connect('/login', ['controller' => 'Login', 'action' => 'login', "prefix" => "ca/api"]);
.. This will look for a class called LoginController, at /src/Controller/Ca/Api/. This class should simply reference your existing default AppController in it's default location:
<?php
namespace App\Controller\Ca\Api;
use App\Controller\AppController; // The namespace declaration is how your subclass locates it's parent class
class LoginController extends AppController
{
If you have some particular need to have multiple AppControllers (which I'd not recommend) then just change what version you're referencing with use namespace.
See for more information:
PHP Namespaces
Prefix Routing
The AppController

Related

Cakephp authentication plugin how can I implement login in admin prefix?

I'm trying to implement cakephp authentication plugin in admin prefix
Route I have written for admin prefix
$routes->prefix('admin', function (RouteBuilder $routes) {
$routes->connect('/',['controller'=>'AdminUsers','action'=>'login']);
$routes->fallbacks(DashedRoute::class);
});
In application.php , I have followed everything That mentioned in authentication documentation
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$authenticationService = new AuthenticationService([
'unauthenticatedRedirect' => Router::url('/admin'),
'queryParam' => 'redirect',
]);
// Load identifiers, ensure we check email and password fields
$authenticationService->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'email',
'password' => 'password',
]
]);
// Load the authenticators, you want session first
$authenticationService->loadAuthenticator('Authentication.Session');
// Configure form data check to pick email and password
$authenticationService->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'email',
'password' => 'password',
],
'userModel' => 'AdminUsers',
'loginUrl' => Router::url('/admin'),
]);
return $authenticationService;
}
I have changed users model to AdminUsers for database table admin_users
Now in admin/appController.php
I have loadComponent in initialize method
$this->loadComponent('Authentication.Authentication');
In before filter method I have added
$this->Authentication->allowUnauthenticated(['login']);
Now after submit login form I am getting error
Table class for alias Users could not be found.
In getAuthenticationService method I have changed model Users to AdminUsers. Why it's going for Users model rather then AdminUsers model ?
My Table/AdminUsersTable.php table class look likes
<?php
declare(strict_types=1);
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class AdminUsersTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->setTable('admin_users');
--------
After ndm comment I am able to change default model in application.php , But how can I change it in Admin/AppController.php ? Code that I have tried.
public function beforeFilter(EventInterface $event)
{
$service = new AuthenticationService();
$service->loadIdentifier('Authentication.Password', [
'resolver' => [
'className' => 'Authentication.Orm',
'userModel' => 'AdminUsers',
],
]);
$this->Authentication->allowUnauthenticated(['login','signup']);
$this->viewBuilder()->setLayout('admin');
}

CakePHP 3: tests for controller

I'm writing tests for a controller in a plugin (Assets plugin).
This is the controller:
namespace Assets\Controller;
use Cake\Controller\Controller;
class AssetsController extends Controller
{
public function asset($filename, $type)
{
$this->response->type($type);
$this->response->file(ASSETS . DS . $filename);
return $this->response;
}
}
As you can see, it only sends an asset files.
This is the route:
Router::plugin('Assets', ['path' => '/assets'], function ($routes) {
$routes->connect(
'/:type/:filename',
['controller' => 'Assets', 'action' => 'asset'],
[
'type' => '(css|js)',
'filename' => '[a-z0-9]+\.(css|js)',
'pass' => ['filename', 'type'],
]
);
});
And this is the test class:
namespace Assets\Test\TestCase\Controller;
use Assets\Utility\AssetsCreator;
use Cake\TestSuite\IntegrationTestCase;
class AssetsControllerTest extends IntegrationTestCase
{
public function testAsset()
{
//This is the filename
$filename = sprintf('%s.%s', AssetsCreator::css('test'), 'css');
$this->get(sprintf('/assets/css/%s', $filename));
$this->assertResponseOk();
}
}
Running the test, however, this exception is generated (full test here):
1) Assets\Test\TestCase\Controller\AssetsControllerTest::testAsset
Cake\Routing\Exception\MissingControllerException: Controller class could not be found. in /home/mirko/Libs/Plugins/Assets/vendor/cakephp/cakephp/src/Http/ControllerFactory.php:91
I do not think is a problem of broken, because the same exception is generated by doing so:
$url = \Cake\Routing\Router::url([
'controller' => 'Assets',
'action' => 'asset',
'plugin' => 'Assets',
'type' => 'css',
'filename' => $filename,
]);
$this->get($url);
Where am I doing wrong? Thanks.
Solved! On my tests' bootstrap, I missed:
DispatcherFactory::add('Routing');
DispatcherFactory::add('ControllerFactory');
Now it works.

'Error: Call to a member function allow() on a non-object' in CakePHP 3 AuthComponent

Following the CakePHP which looks a bit confusing and not so straight forward, I have created a basic authentication logic, however, I cannot seem to load Auth component.
Here is the code part from the AppController.php:
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => ['Form' => ['fields' => ['username' => 'email', 'password' => 'password']]],
'loginAction' => ['controller' => 'Users', 'action' => 'login'],
'loginRedirect' => ['controller' => 'Groups', 'action' => 'index'],
'logoutRedirect' => ['controller' => 'Users', 'action' => 'login']
]);
}
//Allow basic views
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'view', 'display']);
}
Now no matter which controller or action I run, I always receive the following error:
Error: Call to a member function allow() on a non-object
that is referencing the following line:
$this->Auth->allow(['index', 'view', 'display']);
It has to be a straight forward thing, but I just cannot find it in the docummentation, therefore any help or guidance is much appreciated.
Check that your child controller's method initialize() is calling the parent method.
class MyController extends AppController
{
public function initialize() {
parent::initialize();
//rest of code
}
}
I've got this one when I had no Template/Users/login.ctp template created yet
managed to find out only after inspecting the stack-trace obtained by
$e = new \Exception('How did I got here anyway?');
debug($e->getTraceAsString());
yielding
#5 vendor/cakephp/cakephp/src/Error/ExceptionRenderer.php(318): Cake\Controller\Controller->render('missingTemplate')

Display/hide links cakephp 3.0

Sorry im new to cakephp 3.0. In my user table, there are two user types, admin and public. How do I display/hide links according to user types in default.ctp? Can anyone guide me thanks!!
This is my app controller
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
class AppController extends Controller
{
//...
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginRedirect' => [
'controller' => 'Users',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['controller' => 'Users', 'action' => 'add', 'index',
]);
}
}
The AppController you've posted has nothing to do with what I understand of your request so that's got me a little confused. Either way, you can access the session of the current logged in user through session variables.
For example - if your users table had the column 'type' in which the values 'public' or 'admin' were stored, it would look something like this:
<?php if ($this->session->read('Auth.User.type') == 'admin') { ?>
Link to admin functions
<?php } else { ?>
Boring public link
<?php } ?>
That's assuming you're working with logged in users. If you haven't got that far yet, read the CakePHP 3 tutorial on authentication and authorization.

Cakephp 3 - public function add doesn't work with isAuthorized

I have a little problem with the isAuthorized function.
When I use the public function add, isAuthorized doesn't recognize the action request. I changed the name to 'addv' and now it's working. So why? Why can't I use the word 'add'? I used it twice on another project and I used it once on my current project.
Thanks you for you help !
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Event\Event;
use Cake\Validation\Validator;
class VideosController extends AppController{
public function isAuthorized($user){
if(in_array($this->request->action, ['addv'])){
die();
if($user){
return true;
}
}
return parent::isAuthorized($user);
}
public function addv($idc= null,$idg = null){
debug($idc);
debug($this->request->action);
}
}
?>
AppController
class AppController extends Controller {
public function initialize() {
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authorize' => ['Controller'],
'loginRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
$this->loadComponent('RequestHandler');
$this->set('info_session', $this->Auth->user());
}
public function beforeFilter(Event $event){
$this->Auth->allow(['register']);
$this->Auth->allow(['display']);
$this->Auth->allow(['controller' => 'Users', 'action' => 'add']);
}
public function isAuthorized($user){
if(isset($user['grade']) && $user['grade']=== 3){
return true;
}
}
}

Resources