Identifying, authenticating, and authorizing users is a common part of
almost every web application. In CakePHP AuthComponent provides a
pluggable way to do these tasks. AuthComponent allows you to combine
authentication objects and authorization objects to create flexible
ways of identifying and checking user authorization.
Authentication
Authentication is the process of identifying users by provided
credentials and ensuring that users are who they say they are.
Generally, this is done through a username and password, that are checked
against a known list of users. In CakePHP, there are several built-in
ways of authenticating users stored in your application.
FormAuthenticate
allows you to authenticate users based on form POST
data. Usually, this is a login form that users enter information into.
BasicAuthenticate
allows you to authenticate users using Basic HTTP
authentication.
DigestAuthenticate
allows you to authenticate users using Digest
HTTP authentication.
By default AuthComponent
uses FormAuthenticate
.
Choosing an Authentication Type
Generally, you’ll want to offer form based authentication. It is the easiest for
users using a web-browser to use. If you are building an API or webservice, you
may want to consider basic authentication or digest authentication. The key
differences between digest and basic authentication are mostly related to how
passwords are handled. In basic authentication, the username and password are
transmitted as plain-text to the server. This makes basic authentication
un-suitable for applications without SSL, as you would end up exposing sensitive
passwords. Digest authentication uses a digest hash of the username, password,
and a few other details. This makes digest authentication more appropriate for
applications without SSL encryption.
You can also use authentication systems like OpenID as well; however, OpenID is
not part of CakePHP core.
Configuring Authentication Handlers
You configure authentication handlers using the authenticate
config.
You can configure one or many handlers for authentication. Using
multiple handlers allows you to support different ways of logging users
in. When logging users in, authentication handlers are checked in the
order they are declared. Once one handler is able to identify the user,
no other handlers will be checked. Conversely, you can halt all
authentication by throwing an exception. You will need to catch any
thrown exceptions and handle them as needed.
You can configure authentication handlers in your controller’s
beforeFilter()
or initialize()
methods. You can pass
configuration information into each authentication object using an
array:
// Simple setup
$this->Auth->config('authenticate', ['Form']);
// Pass settings in
$this->Auth->config('authenticate', [
'Basic' => ['userModel' => 'Members'],
'Form' => ['userModel' => 'Members']
]);
In the second example, you’ll notice that we had to declare the
userModel
key twice. To help you keep your code DRY, you can use the
all
key. This special key allows you to set settings that are passed
to every attached object. The all
key is also exposed as
AuthComponent::ALL
:
// Pass settings in using 'all'
$this->Auth->config('authenticate', [
AuthComponent::ALL => ['userModel' => 'Members'],
'Basic',
'Form'
]);
In the above example, both Form
and Basic
will get the settings
defined for the ‘all’ key. Any settings passed to a specific
authentication object will override the matching key in the ‘all’ key.
The core authentication objects support the following configuration
keys.
fields
The fields to use to identify a user by. You can use keys
username
and password
to specify your username and password fields
respectively.
userModel
The model name of the users table; defaults to Users.
finder
The finder method to use to fetch a user record. Defaults to ‘all’.
passwordHasher
Password hasher class; Defaults to Default
.
The scope
and contain
options have been deprecated as of 3.1. Use
a custom finder instead to modify the query to fetch a user record.
The userFields
option has been deprecated as of 3.1. Use select()
in
your custom finder.
To configure different fields for user in your initialize()
method:
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email', 'password' => 'passwd']
]
]
]);
}
Do not put other Auth
configuration keys, such as authError
, loginAction
, etc.,
within the authenticate
or Form
element. They should be at the same level as
the authenticate key. The setup above with other Auth configuration
should look like:
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => 'Users',
'action' => 'login',
'plugin' => 'Users'
],
'authError' => 'Did you really think you are allowed to see that?',
'authenticate' => [
'Form' => [
'fields' => ['username' => 'email']
]
],
'storage' => 'Session'
]);
}
In addition to the common configuration, Basic authentication supports
the following keys:
In addition to the common configuration Digest authentication supports
the following keys:
realm
The realm authentication is for. Defaults to the servername.
nonce
A nonce used for authentication. Defaults to uniqid()
.
qop
Defaults to auth; no other values are supported at this time.
opaque
A string that must be returned unchanged by clients. Defaults
to md5($config['realm'])
.
Note
To find the user record, the database is queried only using the username.
The password check is done in PHP. This is necessary because hashing
algorithms like bcrypt (which is used by default) generate a new hash
each time, even for the same string and you can’t just do simple string
comparison in SQL to check if the password matches.
Customizing Find Query
You can customize the query used to fetch the user record using the finder
option in authenticate class config:
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'finder' => 'auth'
]
],
]);
}
This will require your UsersTable
to have finder method findAuth()
.
In the example shown below the query is modified to fetch only required fields
and add a condition. You must ensure that you select the fields you need to
authenticate a user, such as username
and password
:
public function findAuth(\Cake\ORM\Query $query, array $options)
{
$query
->select(['id', 'username', 'password'])
->where(['Users.active' => 1]);
return $query;
}
Note
finder
option is available since 3.1. Prior to that you can use scope
and contain
options to modify a query.
Identifying Users and Logging Them In
-
AuthComponent::
identify
()
You need to manually call $this->Auth->identify()
to identify the user using
credentials provided in request. Then use $this->Auth->setUser()
to log the user in, i.e., save user info to session.
When authenticating users, attached authentication objects are checked
in the order they are attached. Once one of the objects can identify
the user, no other objects are checked. A sample login function for
working with a login form could look like:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
return $this->redirect($this->Auth->redirectUrl());
} else {
$this->Flash->error(__('Username or password is incorrect'));
}
}
}
The above code will attempt to first identify a user by using the POST data.
If successful we set the user info to the session so that it persists across requests
and then redirect to either the last page they were visiting or a URL specified in the
loginRedirect
config. If the login is unsuccessful, a flash message is set.
Warning
$this->Auth->setUser($data)
will log the user in with whatever data is
passed to the method. It won’t actually check the credentials against an
authentication class.
Redirecting Users After Login
-
AuthComponent::
redirectUrl
()
After logging a user in, you’ll generally want to redirect them back to where
they came from. Pass a URL in to set the destination a user should be redirected
to after logging in.
If no parameter is passed, the returned URL will use the following rules:
Returns the normalized URL from the redirect
query string value if it is
present and for the same domain the current app is running on. Before 3.4.0,
the Auth.redirect
session value was used.
If there is no query string/session value and there is a config with
loginRedirect
, the loginRedirect
value is returned.
If there is no redirect value and no loginRedirect
, /
is returned.
Creating Stateless Authentication Systems
Basic and digest are stateless authentication schemes and don’t require an
initial POST or a form. If using only basic/digest authenticators you don’t
require a login action in your controller. Stateless authentication will
re-verify the user’s credentials on each request, this creates a small amount of
additional overhead, but allows clients to login without using cookies and
makes AuthComponent more suitable for building APIs.
For stateless authenticators, the storage
config should be set to Memory
so that AuthComponent does not use a session to store user record. You may also
want to set config unauthorizedRedirect
to false
so that AuthComponent
throws a ForbiddenException
instead of the default behavior of redirecting to
referrer.
The unauthorizedRedirect
option only applies to authenticated users. When
a user is not yet authenticated and you do not want the user to be redirected,
you will need to load one or more stateless authenticators, like Basic
or
Digest
.
Authentication objects can implement a getUser()
method that can be used to
support user login systems that don’t rely on cookies. A typical getUser method
looks at the request/environment and uses the information there to confirm the
identity of the user. HTTP Basic authentication for example uses
$_SERVER['PHP_AUTH_USER']
and $_SERVER['PHP_AUTH_PW']
for the username
and password fields.
Note
In case authentication does not work like expected, check if queries
are executed at all (see BaseAuthenticate::_query($username)
).
In case no queries are executed check if $_SERVER['PHP_AUTH_USER']
and $_SERVER['PHP_AUTH_PW']
do get populated by the webserver.
If you are using Apache with FastCGI-PHP you might need to add this line
to your .htaccess file in webroot:
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
On each request, these values, PHP_AUTH_USER
and PHP_AUTH_PW
, are used to
re-identify the user and ensure they are the valid user. As with authentication
object’s authenticate()
method, the getUser()
method should return
an array of user information on the success or false
on failure.
public function getUser(ServerRequest $request)
{
$username = env('PHP_AUTH_USER');
$pass = env('PHP_AUTH_PW');
if (empty($username) || empty($pass)) {
return false;
}
return $this->_findUser($username, $pass);
}
The above is how you could implement the getUser method for HTTP basic
authentication. The _findUser()
method is part of BaseAuthenticate
and identifies a user based on a username and password.
Using Basic Authentication
Basic authentication allows you to create a stateless authentication that can be
used in intranet applications or for simple API scenarios. Basic authentication
credentials will be rechecked on each request.
Warning
Basic authentication transmits credentials in plain-text. You should use
HTTPS when using Basic authentication.
To use basic authentication, you’ll need to configure AuthComponent:
$this->loadComponent('Auth', [
'authenticate' => [
'Basic' => [
'fields' => ['username' => 'username', 'password' => 'api_key'],
'userModel' => 'Users'
],
],
'storage' => 'Memory',
'unauthorizedRedirect' => false
]);
Here we’re using username + API key as our fields and use the Users model.
Creating API Keys for Basic Authentication
Because basic HTTP sends credentials in plain-text, it is unwise to have users
send their login password. Instead, an opaque API key is generally used. You can
generate these API tokens randomly using libraries from CakePHP:
namespace App\Model\Table;
use Cake\Auth\DefaultPasswordHasher;
use Cake\Utility\Text;
use Cake\Event\Event;
use Cake\ORM\Table;
use Cake\Utility\Security;
class UsersTable extends Table
{
public function beforeSave(Event $event)
{
$entity = $event->getData('entity');
if ($entity->isNew()) {
$hasher = new DefaultPasswordHasher();
// Generate an API 'token'
$entity->api_key_plain = Security::hash(Security::randomBytes(32), 'sha256', false);
// Bcrypt the token so BasicAuthenticate can check
// it during login.
$entity->api_key = $hasher->hash($entity->api_key_plain);
}
return true;
}
}
The above generates a random hash for each user as they are saved. The above
code assumes you have two columns api_key
- to store the hashed API key, and
api_key_plain
- to the plaintext version of the API key, so we can display
it to the user later on. Using a key instead of a password means that even over
plain HTTP, your users can use an opaque token instead of their original
password. It is also wise to include logic allowing API keys to be regenerated
at a user’s request.
Using Digest Authentication
Digest authentication offers an improved security model over basic
authentication, as the user’s credentials are never sent in the request header.
Instead, a hash is sent.
To use digest authentication, you’ll need to configure AuthComponent
:
$this->loadComponent('Auth', [
'authenticate' => [
'Digest' => [
'fields' => ['username' => 'username', 'password' => 'digest_hash'],
'userModel' => 'Users'
],
],
'storage' => 'Memory',
'unauthorizedRedirect' => false
]);
Here we’re using username + digest_hash as our fields and use the Users model.
Hashing Passwords For Digest Authentication
Because Digest authentication requires a password hashed in the format
defined by the RFC, in order to correctly hash a password for use with
Digest authentication you should use the special password hashing
function on DigestAuthenticate
. If you are going to be combining
digest authentication with any other authentication strategies, it’s also
recommended that you store the digest password in a separate column,
from the normal password hash:
namespace App\Model\Table;
use Cake\Auth\DigestAuthenticate;
use Cake\Event\Event;
use Cake\ORM\Table;
class UsersTable extends Table
{
public function beforeSave(Event $event)
{
$entity = $event->getData('entity');
// Make a password for digest auth.
$entity->digest_hash = DigestAuthenticate::password(
$entity->username,
$entity->plain_password,
env('SERVER_NAME')
);
return true;
}
}
Passwords for digest authentication need a bit more information than
other password hashes, based on the RFC for digest authentication.
Note
The third parameter of DigestAuthenticate::password()
must match the
‘realm’ config value defined when DigestAuthentication was configured
in AuthComponent::$authenticate
. This defaults to env('SCRIPT_NAME')
.
You may wish to use a static string if you want consistent hashes in multiple environments.
Creating Custom Authentication Objects
Because authentication objects are pluggable, you can create custom
authentication objects in your application or plugins. If for example,
you wanted to create an OpenID authentication object. In
src/Auth/OpenidAuthenticate.php you could put the following:
namespace App\Auth;
use Cake\Auth\BaseAuthenticate;
use Cake\Http\ServerRequest;
use Cake\Http\Response;
class OpenidAuthenticate extends BaseAuthenticate
{
public function authenticate(ServerRequest $request, Response $response)
{
// Do things for OpenID here.
// Return an array of user if they could authenticate the user,
// return false if not.
}
}
Authentication objects should return false
if they cannot identify the
user and an array of user information if they can. It’s not required
that you extend BaseAuthenticate
, only that your authentication object
implements Cake\Event\EventListenerInterface
. The BaseAuthenticate
class
provides a number of helpful methods that are commonly used. You can
also implement a getUser()
method if your authentication object needs
to support stateless or cookie-less authentication. See the sections on
basic and digest authentication below for more information.
AuthComponent
triggers two events, Auth.afterIdentify
and Auth.logout
,
after a user has been identified and before a user is logged out respectively.
You can set callback functions for these events by returning a mapping array
from implementedEvents()
method of your authenticate class:
public function implementedEvents()
{
return [
'Auth.afterIdentify' => 'afterIdentify',
'Auth.logout' => 'logout'
];
}
Using Custom Authentication Objects
Once you’ve created your custom authentication objects, you can use them
by including them in AuthComponent
’s authenticate array:
$this->Auth->config('authenticate', [
'Openid', // app authentication object.
'AuthBag.Openid', // plugin authentication object.
]);
Note
Note that when using simple notation there’s no ‘Authenticate’ word when
initiating the authentication object. Instead, if using namespaces, you’ll
need to set the full namespace of the class, including the ‘Authenticate’ word.
Handling Unauthenticated Requests
When an unauthenticated user tries to access a protected page first the
unauthenticated()
method of the last authenticator in the chain is called.
The authenticate object can handle sending response or redirection by returning
a response object to indicate no further action is necessary. Due to this, the
order in which you specify the authentication provider in authenticate
config matters.
If authenticator returns null, AuthComponent
redirects user to the login action.
If it’s an AJAX request and config ajaxLogin
is specified that element
is rendered else a 403 HTTP status code is returned.
Hashing Passwords
You are responsible for hashing the passwords before they are persisted to the
database, the easiest way is to use a setter function in your User entity:
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
class User extends Entity
{
// ...
protected function _setPassword($password)
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher)->hash($password);
}
}
// ...
}
AuthComponent
is configured by default to use the DefaultPasswordHasher
when validating user credentials so no additional configuration is required in
order to authenticate users.
DefaultPasswordHasher
uses the bcrypt hashing algorithm internally, which
is one of the stronger password hashing solutions used in the industry. While it
is recommended that you use this password hasher class, the case may be that you
are managing a database of users whose password was hashed differently.
Creating Custom Password Hasher Classes
In order to use a different password hasher, you need to create the class in
src/Auth/LegacyPasswordHasher.php and implement the
hash()
and check()
methods. This class needs to extend the
AbstractPasswordHasher
class:
namespace App\Auth;
use Cake\Auth\AbstractPasswordHasher;
class LegacyPasswordHasher extends AbstractPasswordHasher
{
public function hash($password)
{
return sha1($password);
}
public function check($password, $hashedPassword)
{
return sha1($password) === $hashedPassword;
}
}
Then you are required to configure the AuthComponent
to use your own password
hasher:
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'passwordHasher' => [
'className' => 'Legacy',
]
]
]
]);
}
Supporting legacy systems is a good idea, but it is even better to keep your
database with the latest security advancements. The following section will
explain how to migrate from one hashing algorithm to CakePHP’s default.
Changing Hashing Algorithms
CakePHP provides a clean way to migrate your users’ passwords from one algorithm
to another, this is achieved through the FallbackPasswordHasher
class.
Assuming you are migrating your app from CakePHP 2.x which uses sha1
password hashes, you
can configure the AuthComponent
as follows:
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'passwordHasher' => [
'className' => 'Fallback',
'hashers' => [
'Default',
'Weak' => ['hashType' => 'sha1']
]
]
]
]
]);
}
The first name appearing in the hashers
key indicates which of the classes
is the preferred one, but it will fallback to the others in the list if the
check was unsuccessful.
When using the WeakPasswordHasher
you will need to
set the Security.salt
configure the value to ensure passwords are salted.
In order to update old users’ passwords on the fly, you can change the login
function accordingly:
public function login()
{
if ($this->request->is('post')) {
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
if ($this->Auth->authenticationProvider()->needsPasswordRehash()) {
$user = $this->Users->get($this->Auth->user('id'));
$user->password = $this->request->getData('password');
$this->Users->save($user);
}
return $this->redirect($this->Auth->redirectUrl());
}
...
}
}
As you can see we are just setting the plain password again so the setter
function in the entity will hash the password as shown in the previous example and
then save the entity.
Manually Logging Users In
-
AuthComponent::
setUser
(array $user)
Sometimes the need arises where you need to manually log a user in, such
as just after they registered for your application. You can do this by
calling $this->Auth->setUser()
with the user data you want to ‘login’:
public function register()
{
$user = $this->Users->newEntity($this->request->getData());
if ($this->Users->save($user)) {
$this->Auth->setUser($user->toArray());
return $this->redirect([
'controller' => 'Users',
'action' => 'home'
]);
}
}
Warning
Be sure to manually add the new User id to the array passed to the setUser()
method. Otherwise, you won’t have the user id available.
Accessing the Logged In User
-
AuthComponent::
user
($key = null)
Once a user is logged in, you will often need some particular
information about the current user. You can access the currently logged
in user using AuthComponent::user()
:
// From inside a controller or other component.
$this->Auth->user('id');
If the current user is not logged in or the key doesn’t exist, null will
be returned.
Logging Users Out
-
AuthComponent::
logout
()
Eventually, you’ll want a quick way to de-authenticate someone and
redirect them to where they need to go. This method is also useful if
you want to provide a ‘Log me out’ link inside a members’ area of your
application:
public function logout()
{
return $this->redirect($this->Auth->logout());
}
Logging out users that logged in with Digest or Basic auth is difficult
to accomplish for all clients. Most browsers will retain credentials
for the duration they are still open. Some clients can be forced to
logout by sending a 401 status code. Changing the authentication realm
is another solution that works for some clients.
Deciding When to run Authentication
In some cases you may want to use $this->Auth->user()
in the
beforeFilter(Event $event)
method. This is achievable by using the
checkAuthIn
config key. The following changes which event for which initial
authentication checks should be done:
//Set up AuthComponent to authenticate in initialize()
$this->Auth->config('checkAuthIn', 'Controller.initialize');
Default value for checkAuthIn
is 'Controller.startup'
- but by using
'Controller.initialize'
initial authentication is done before beforeFilter()
method.
Authorization
Authorization is the process of ensuring that an
identified/authenticated user is allowed to access the resources they
are requesting. If enabled AuthComponent
can automatically check
authorization handlers and ensure that logged in users are allowed to
access the resources they are requesting. There are several built-in
authorization handlers and you can create custom ones for your
application or as part of a plugin.
Note
The ActionsAuthorize
& CrudAuthorize
adapter available in CakePHP
2.x have now been moved to a separate plugin cakephp/acl.
Configuring Authorization Handlers
You configure authorization handlers using the authorize
config key.
You can configure one or many handlers for authorization. Using
multiple handlers allows you to support different ways of checking
authorization. When authorization handlers are checked, they will be
called in the order they are declared. Handlers should return false
, if
they are unable to check authorization, or the check has failed.
Handlers should return true
if they were able to check authorization
successfully. Handlers will be called in sequence until one passes. If
all checks fail, the user will be redirected to the page they came from.
Additionally, you can halt all authorization by throwing an exception.
You will need to catch any thrown exceptions and handle them.
You can configure authorization handlers in your controller’s
beforeFilter()
or initialize()
methods. You can pass
configuration information into each authorization object, using an
array:
// Basic setup
$this->Auth->config('authorize', ['Controller']);
// Pass settings in
$this->Auth->config('authorize', [
'Actions' => ['actionPath' => 'controllers/'],
'Controller'
]);
Much like authenticate
, authorize
, helps you
keep your code DRY, by using the all
key. This special key allows you
to set settings that are passed to every attached object. The all
key
is also exposed as AuthComponent::ALL
:
// Pass settings in using 'all'
$this->Auth->config('authorize', [
AuthComponent::ALL => ['actionPath' => 'controllers/'],
'Actions',
'Controller'
]);
In the above example, both the Actions
and Controller
will get the
settings defined for the ‘all’ key. Any settings passed to a specific
authorization object will override the matching key in the ‘all’ key.
If an authenticated user tries to go to a URL they are not authorized to access,
they will be redirected back to the referrer. If you do not want such redirection
(mostly needed when using stateless authentication adapter) you can set config
option unauthorizedRedirect
to false
. This causes AuthComponent
to throw a ForbiddenException
instead of redirecting.
Creating Custom Authorize Objects
Because authorize objects are pluggable, you can create custom authorize
objects in your application or plugins. If for example, you wanted to
create an LDAP authorize object. In
src/Auth/LdapAuthorize.php you could put the
following:
namespace App\Auth;
use Cake\Auth\BaseAuthorize;
use Cake\Http\ServerRequest;
class LdapAuthorize extends BaseAuthorize
{
public function authorize($user, ServerRequest $request)
{
// Do things for ldap here.
}
}
Authorize objects should return false
if the user is denied access, or
if the object is unable to perform a check. If the object is able to
verify the user’s access, true
should be returned. It’s not required
that you extend BaseAuthorize
, only that your authorize object
implements an authorize()
method. The BaseAuthorize
class provides
a number of helpful methods that are commonly used.
Using Custom Authorize Objects
Once you’ve created your custom authorize object, you can use them by
including them in your AuthComponent
’s authorize array:
$this->Auth->config('authorize', [
'Ldap', // app authorize object.
'AuthBag.Combo', // plugin authorize object.
]);
Using No Authorization
If you’d like to not use any of the built-in authorization objects and
want to handle things entirely outside of AuthComponent
, you can set
$this->Auth->config('authorize', false);
. By default AuthComponent
starts off with authorize
set to false
. If you don’t use an
authorization scheme, make sure to check authorization yourself in your
controller’s beforeFilter()
or with another component.
Making Actions Public
-
AuthComponent::
allow
($actions = null)
There are often times controller actions that you wish to remain
entirely public or that don’t require users to be logged in.
AuthComponent
is pessimistic and defaults to denying access. You can
mark actions as public actions by using AuthComponent::allow()
. By
marking actions as public, AuthComponent
will not check for a logged in
user nor will authorize objects to be checked:
// Allow all actions
$this->Auth->allow();
// Allow only the index action.
$this->Auth->allow('index');
// Allow only the view and index actions.
$this->Auth->allow(['view', 'index']);
By calling it empty you allow all actions to be public.
For a single action, you can provide the action name as a string. Otherwise, use an array.
Note
You should not add the “login” action of your UsersController
to allow list.
Doing so would cause problems with the normal functioning of AuthComponent
.
Making Actions Require Authorization
-
AuthComponent::
deny
($actions = null)
By default all actions require authorization. However, after making actions
public you want to revoke the public access. You can do so using
AuthComponent::deny()
:
// Deny all actions.
$this->Auth->deny();
// Deny one action
$this->Auth->deny('add');
// Deny a group of actions.
$this->Auth->deny(['add', 'edit']);
By calling it empty you deny all actions.
For a single action, you can provide the action name as a string. Otherwise, use an array.
Using ControllerAuthorize
ControllerAuthorize allows you to handle authorization checks in a
controller callback. This is ideal when you have very simple
authorization or you need to use a combination of models and components
to do your authorization and don’t want to create a custom authorize
object.
The callback is always called isAuthorized()
and it should return a
boolean as to whether or not the user is allowed to access resources in
the request. The callback is passed the active user so it can be
checked:
class AppController extends Controller
{
public function initialize()
{
parent::initialize();
$this->loadComponent('Auth', [
'authorize' => 'Controller',
]);
}
public function isAuthorized($user = null)
{
// Any registered user can access public functions
if (!$this->request->getParam('prefix')) {
return true;
}
// Only admins can access admin functions
if ($this->request->getParam('prefix') === 'admin') {
return (bool)($user['role'] === 'admin');
}
// Default deny
return false;
}
}
The above callback would provide a very simple authorization system
where only users with role = admin could access actions that were in
the admin prefix.