Closed asgraf closed 1 year ago
You need to use AuthenticationComponent::setIdentity()
to update the identity in session after modifying its database record.
So you are telling me that 'identify' => true does nothing by design?
It doesn't do what you think it does. It uses the existing session identity to find matching record in the db. If you change the db record you have to explicitly update the session identity.
To expand on @ADmad 's point. The identify
option is useful when you need a way to revoke authentication/session. For example deactivating a user's account for abusive behavior.
I'm trying to read $identity->fraud boolean field to restrict number of payment options available to logged in user. Like i said in earlier post, since request to database is already done why this value is just discarded. I don't see sense of why i need to make second identical request to database myself to update session. Why not have at least an option to update session with this already fetched from database fresh value?
Having the option to set the identity refetched from db to the session does make sense.
Having the option to set the identity refetched from db to the session does make sense.
This is why I don't rely on the identity for anything but id and password.
I agree that updating the session value, or at the very least ensuring that the identity
request attribute always reflects the identified user makes sense.
I took a look at the existing code, and it should already be using the newly fetched user as $this->request->getAttribute('identity')
or from $authService->getIdentity()
. Starting here in
AuthenticationService.
We see the authenticators being used to authenticate the user. When using SessionAuthenticator with identify=true
we end up here.
This includes the fresh user fetched from the database. Then in the middleware the service's identity is set to the request attribute:
How are you accessing a stale user record?
Seems he might be directly accessing the session instead of getting the identity through the request or the authn service.
Seems he might be directly accessing the session instead of getting the identity through the request or the authn service.
So don't do that is the solution.
Seems he might be directly accessing the session instead of getting the identity through the request or the authn service.
In code I'm accessing identity only by using AutenticatorComponent, IdentityHelper or by $request->getAttribute('identity') directly (because internal implementation of SessionAuthenticator can change in future) But during development indeed i was looking at DebugKit Toolbar's Session tab to see if values are updating instead of dumping $request->getAttribute('identity') directly
Maybe i will try to explain what im trying to achieve. Currently you can have identity refreshed every web request or never. Basically i was experimenting with refreshing identity every few minutes and/or before/after some important actions Here are my experiments:
$authenticationService->loadAuthenticator('Authentication.Session', [
'fields' => [IdentifierInterface::CREDENTIAL_USERNAME => 'email'],
'identify' => $request->is(['POST', 'PUT', 'PATCH', 'DELETE']),
]);
//my custom IdentityRefreshComponent, method called in important actions
public function refreshIdentity(): ResultInterface
{
$authenticationComponent = $this->getAuthenticationComponent();
$identity = $authenticationComponent->getIdentity();
$authenticator = $authenticationComponent->getAuthenticationService()->getAuthenticationProvider();
if (
$identity instanceof IdentityInterface &&
$authenticator instanceof SessionAuthenticator
) {
if (!($identity instanceof EntityInterface)) {
throw new InternalErrorException('Identity does not implement EntityInterface');
}
$authenticator->setConfig('identify', true);
$result = $authenticator->authenticate($this->getController()->getRequest());
if ($result->isValid()) {
$authenticationComponent->setIdentity($result->getData());
}
return $result;
}
return new Result(null, ResultInterface::FAILURE_OTHER);
}
Basically i was experimenting with refreshing identity every few minutes and/or before/after some important actions Here are my experiments:
This sounds like behavior that would require a custom Authenticator that behaves like SessionAuthenticator
but also handles periodic refreshes.
Here are some more code snippets from my experiments Refreshing identity on save:
$eventManager = EventManager::instance();
\assert($eventManager instanceof EventManager);
$eventManager->on(
'Model.afterSaveCommit',
function (EventInterface $event, EntityInterface $entity, ArrayObject $options) use ($identity) {
if (
$entity instanceof IdentityInterface &&
$entity::class === $identity::class &&
$entity->getIdentifier() === $identity->getIdentifier()
) {
$this->IdentityRefresh->refreshIdentity();//source code in my previous comment
}
}
);
Refreshing identity every few X minutes
$interval = MINUTE;//example
if ($identity->modified->addSeconds($interval)->isPast()) {
$table = TableRegistry::getTableLocator()->get($identity->getSource());
$identity->modified = FrozenTime::now();
$table->saveOrFail($identity);//this will trigger identity refresh on save
}
This issue is stale because it has been open for 120 days with no activity. Remove the stale
label or comment or this will be closed in 15 days
What i did:
After logging in, i manually modified logged user database row and refreshed page and identity in session did not update.
After investigation i have determined that new and updated identity that was indeed fetched from database but this condition resolves to false and this new identity value is never written to session