Authentication 3 plugin error

Hey! everyone!

I am getting error in cakephp 5 with authentication plugin

Fatal error: Declaration of App\Model\Entity\User::applyScope($action, $resource) must be compatible with Authorization\IdentityInterface::applyScope(string $action, mixed $resource, mixed …$optionalArgs): mixed in /var/www/html/evo/src/Model/Entity/User.php on line 123

please help me

adjust your methods to the new method signature as the error says

See authorization/src/IdentityDecorator.php at 3.x · cakephp/authorization · GitHub on how it should look like

I am also confused why you need applyScope on a User entity…

hehhehehe… actually i have different ID column in users table…>

public function getIdentifier()
{
return $this->reffer_id;
}

so because this(reffer_id) i have to define all that methods into user entity… if you any suggestion please kindly guide me @KevinPfeifer and please demo code… for adjust your methods to the new method signature as the error says(any example).

Thats why I gave you the link from above but let me just copy paste the code in here

public function applyScope(string $action, mixed $resource, mixed ...$optionalArgs): mixed
{
    return $this->authorization->applyScope($this, $action, $resource, ...$optionalArgs);
}

you will also need to adjust this

public function getOriginalData(): \ArrayAccess|array
{
    return $this;
}

because as you can see CakePHP 5 has added parameter as well as return types.

And object oriented PHP requires overwritten methods (which you have here) to be defined the same as they are in their parents/interfaces.

What I want to say with this is the fact, that this is not a CakePHP specific error but a general PHP error which you should learn to understand and fix yourself in the future because they may come up more often.

I can’t tell you if your system is acutally good or not, it just feels weird to me

Also the authorization plugin provides a Identity Decorator for stuff like that as you can see here:
https://book.cakephp.org/authorization/3/en/checking-authorization.html

You then don’t need to implement what you do

Ah! I got it @KevinPfeifer thanks. It means that I can do same things from the policies and can validate what should guest can access… Am I right?

policies as well as scopes get the currently logged in user passed in. See my workshop video

But getIdentifier not working in policies… because I want to replace the Id… with refer_id, it is not working in Entity policy or Table Policy.

public function getIdentifier()
{
return $this->refer_id;
}

Ok…sure i will check @KevinPfeifer

it return null now…hehhehhehe

well how did you set the authorization service in the entity previously if this worked in cake4

I just checked the docs. Make sure you have this inside your entity as well

    public function setAuthorization(AuthorizationServiceInterface $service)
    {
        $this->authorization = $service;

        return $this;
    }

The docs in Authorization Middleware - 3.x need to be updated so they are not 100% correct

yeah cakephp 4 work perfectly but in cakephp 5 raise error at this step

> <?php
> 
> declare(strict_types=1);
> 
> namespace App\Model\Entity;
> 
> use Cake\ORM\Entity;
> 
> use Authentication\PasswordHasher\DefaultPasswordHasher;
> use Authorization\IdentityInterface as AuthorizationIdentity;
> use Authentication\IdentityInterface as AuthenticationIdentity;
> use Authorization\AuthorizationServiceInterface;
> use Authorization\IdentityInterface;
> use Authorization\Policy\ResultInterface;
> 
> /**
>  * User Entity
>  *
>  * @property int $id
>  * @property string|null $username
>  * @property string|null $email
>  * @property string|null $password
>  * @property string|null $token
>  * @property \Cake\I18n\DateTime|null $token_expire
>  * @property \Cake\I18n\DateTime|null $token_expiration
>  * @property int|null $userkeyid
>  * @property string|null $api_token
>  * @property \Cake\I18n\DateTime|null $activation_date
>  * @property float|null $longitude
>  * @property float|null $latitude
>  * @property int|null $active
>  * @property \Cake\I18n\DateTime|null $tos_date
>  * @property string|null $secret
>  * @property int|null $secret_verified
>  * @property string|null $account_verify
>  * @property int|null $is_superuser
>  * @property int|null $role_id
>  * @property \Cake\I18n\Date|null $join_date
>  * @property \Cake\I18n\DateTime|null $login_time
>  * @property \Cake\I18n\DateTime|null $logout_time
>  * @property \Cake\I18n\DateTime|null $created
>  * @property \Cake\I18n\DateTime|null $modified
>  * @property \Cake\I18n\DateTime|null $trashed
>  *
>  * @property \App\Model\Entity\Role[] $roles
>  * @property \App\Model\Entity\Profile[] $profiles
>  */
> class User extends Entity implements AuthorizationIdentity, AuthenticationIdentity
> {
>     /**
>      * Fields that can be mass assigned using newEntity() or patchEntity().
>      *
>      * Note that when '*' is set to true, this allows all unspecified fields to
>      * be mass assigned. For security purposes, it is advised to set '*' to false
>      * (or remove it), and explicitly make individual fields accessible as needed.
>      *
>      * @var array<string, bool>
>      */
>     protected array $_accessible = [
>         'username' => true,
>         'email' => true,
>         'password' => true,
>         'token' => true,
>         'token_expire' => true,
>         'token_expiration' => true,
>         'refer_id' => true,
>         'api_token' => true,
>         'activation_date' => true,
>         'longitude' => true,
>         'latitude' => true,
>         'active' => true,
>         'tos_date' => true,
>         'secret' => true,
>         'secret_verified' => true,
>         'account_verify' => true,
>         'is_superuser' => true,
>         'role_id' => true,
>         'join_date' => true,
>         'login_time' => true,
>         'logout_time' => true,
>         'created' => true,
>         'modified' => true,
>         'trashed' => true,
>         'roles' => true,
>         'profile' => true,
>     ];
> 
>     /**
>      * Fields that are excluded from JSON versions of the entity.
>      *
>      * @var array<string>
>      */
>     protected array $_hidden = [
>         'password',
>         'token',
>     ];
> 
>     protected function _setPassword(string $password)
>     {
>         $hasher = new DefaultPasswordHasher();
>         return $hasher->hash($password);
>     }
> 
>     /**
>      * Authorization\IdentityInterface method
>      */
>     public function can($action, $resource): bool
>     {
>         return $this->authorization->can($this, $action, $resource);
>     }
> 
>     /**
>      * Authorization\IdentityInterface method
>      */
>     public function canResult($action, $resource): ResultInterface
>     {
>         return $this->authorization->canResult($this, $action, $resource);
>     }
> 
>     /**
>      * Authorization\IdentityInterface method
>      */
>     public function applyScope(string $action, mixed $resource, mixed ...$optionalArgs): mixed
>     {
>         return $this->authorization->applyScope($this, $action, $resource, ...$optionalArgs);
>     }
> 
>     /**
>      * Authorization\IdentityInterface method
>      */
>     public function getOriginalData(): \ArrayAccess|array
>     {
>         return $this;
>     }
> 
>     /**
>      * Setter to be used by the middleware.
>      */
>     public function setAuthorization(AuthorizationServiceInterface $service)
>     {
>         $this->authorization = $service;
> 
>         return $this;
>     }
> 
>     public function getIdentifier(): int
>     {
>         return $this->refer_id;
>     }
> }

Well that is fine but did you also follow the docs to add

    $middlewareQueue->add(new AuthorizationMiddleware($this, [
        'identityDecorator' => function ($auth, $user) {
            return $user->setAuthorization($auth);
        }
    ]));

in your middlewarequeue?

already define @KevinPfeifer but yes its work now thanks a lot @KevinPfeifer

->add(new AuthorizationMiddleware($this, [
                'unauthorizedHandler' => [
                    'className' => 'Authorization.Redirect',
                    'url' => '/accounts/login',
                    'queryParam' => 'redirectUrl',
                    'exceptions' => [
                        MissingIdentityException::class,
                        ForbiddenException::class
                    ],
                ],
                'identityDecorator' => function ($auth, $user) {
                    return $user->setAuthorization($auth);
                }
            ]))

the docs will soon be updated. Happy that it works now

yes! docs must be updated and thank to help me @KevinPfeifer cakephp is best framework

Thanks for the nice words but there are always things to improve :wink:

1 Like