Skip to content

Commit cfc37d6

Browse files
committed
Add default TokenIdentifier for PrimaryKeySessionAuthenticator
PrimaryKeySessionAuthenticator now works out of the box without requiring explicit identifier configuration. When no identifier is provided, it lazily creates a TokenIdentifier configured to look up users by their `id` field. Before: ```php $service->loadAuthenticator('Authentication.PrimaryKeySession', [ 'identifier' => [ 'className' => 'Authentication.Token', 'tokenField' => 'id', 'dataField' => 'key', ], ]); ``` After: ```php $service->loadAuthenticator('Authentication.PrimaryKeySession'); ``` Custom configuration is still supported by passing an explicit identifier or by using the `idField` and `identifierKey` config options which propagate to the default TokenIdentifier.
1 parent 7aa5be8 commit cfc37d6

2 files changed

Lines changed: 132 additions & 8 deletions

File tree

src/Authenticator/PrimaryKeySessionAuthenticator.php

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,95 @@
44
namespace Authentication\Authenticator;
55

66
use ArrayAccess;
7+
use Authentication\Identifier\IdentifierFactory;
78
use Authentication\Identifier\IdentifierInterface;
89
use Cake\Http\Exception\UnauthorizedException;
910
use Psr\Http\Message\ResponseInterface;
1011
use Psr\Http\Message\ServerRequestInterface;
1112

1213
/**
1314
* Session Authenticator with only ID
15+
*
16+
* This authenticator stores only the user's primary key in the session,
17+
* and looks up the full user record from the database on each request.
18+
*
19+
* By default, it uses a TokenIdentifier configured to look up users by
20+
* their `id` field. This works out of the box for most applications:
21+
*
22+
* ```php
23+
* $service->loadAuthenticator('Authentication.PrimaryKeySession');
24+
* ```
25+
*
26+
* You can customize the identifier configuration if needed:
27+
*
28+
* ```php
29+
* $service->loadAuthenticator('Authentication.PrimaryKeySession', [
30+
* 'identifier' => [
31+
* 'className' => 'Authentication.Token',
32+
* 'tokenField' => 'uuid',
33+
* 'dataField' => 'key',
34+
* 'resolver' => [
35+
* 'className' => 'Authentication.Orm',
36+
* 'userModel' => 'Members',
37+
* ],
38+
* ],
39+
* ]);
40+
* ```
1441
*/
1542
class PrimaryKeySessionAuthenticator extends SessionAuthenticator
1643
{
1744
/**
18-
* @param \Authentication\Identifier\IdentifierInterface|null $identifier
19-
* @param array<string, mixed> $config
45+
* Default config for this object.
46+
*
47+
* - `identifierKey` The key used when passing the ID to the identifier.
48+
* - `idField` The field on the user entity that contains the primary key.
49+
*
50+
* @var array<string, mixed>
51+
*/
52+
protected array $_defaultConfig = [
53+
'fields' => [],
54+
'sessionKey' => 'Auth',
55+
'impersonateSessionKey' => 'AuthImpersonate',
56+
'identify' => false,
57+
'identityAttribute' => 'identity',
58+
'identifierKey' => 'key',
59+
'idField' => 'id',
60+
];
61+
62+
/**
63+
* Constructor
64+
*
65+
* Bypasses SessionAuthenticator's default PasswordIdentifier creation
66+
* to allow lazy initialization of the TokenIdentifier in getIdentifier().
67+
*
68+
* @param \Authentication\Identifier\IdentifierInterface|null $identifier Identifier instance.
69+
* @param array<string, mixed> $config Configuration settings.
2070
*/
2171
public function __construct(?IdentifierInterface $identifier, array $config = [])
2272
{
23-
$config += [
24-
'identifierKey' => 'key',
25-
'idField' => 'id',
26-
];
73+
$this->_identifier = $identifier;
74+
$this->setConfig($config);
75+
}
76+
77+
/**
78+
* Gets the identifier.
79+
*
80+
* If no identifier was explicitly configured, creates a default TokenIdentifier
81+
* configured to look up users by their primary key (`id` field).
82+
*
83+
* @return \Authentication\Identifier\IdentifierInterface
84+
*/
85+
public function getIdentifier(): IdentifierInterface
86+
{
87+
if ($this->_identifier === null) {
88+
$this->_identifier = IdentifierFactory::create([
89+
'className' => 'Authentication.Token',
90+
'tokenField' => $this->getConfig('idField'),
91+
'dataField' => $this->getConfig('identifierKey'),
92+
]);
93+
}
2794

28-
parent::__construct($identifier, $config);
95+
return $this->_identifier;
2996
}
3097

3198
/**

tests/TestCase/Authenticator/PrimaryKeySessionAuthenticatorTest.php

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public function setUp(): void
6767
}
6868

6969
/**
70-
* Test authentication
70+
* Test authentication with explicit identifier
7171
*
7272
* @return void
7373
*/
@@ -89,6 +89,63 @@ public function testAuthenticateSuccess()
8989
$this->assertSame(Result::SUCCESS, $result->getStatus());
9090
}
9191

92+
/**
93+
* Test authentication works with default identifier (no explicit configuration)
94+
*
95+
* @return void
96+
*/
97+
public function testAuthenticateSuccessWithDefaultIdentifier()
98+
{
99+
$request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/']);
100+
101+
$this->sessionMock->expects($this->once())
102+
->method('read')
103+
->with('Auth')
104+
->willReturn(1);
105+
106+
$request = $request->withAttribute('session', $this->sessionMock);
107+
108+
// No identifier passed - should use the default TokenIdentifier
109+
$authenticator = new PrimaryKeySessionAuthenticator(null);
110+
$result = $authenticator->authenticate($request);
111+
112+
$this->assertInstanceOf(Result::class, $result);
113+
$this->assertSame(Result::SUCCESS, $result->getStatus());
114+
}
115+
116+
/**
117+
* Test getIdentifier returns default TokenIdentifier when none configured
118+
*
119+
* @return void
120+
*/
121+
public function testGetIdentifierReturnsDefaultWhenNotConfigured()
122+
{
123+
$authenticator = new PrimaryKeySessionAuthenticator(null);
124+
$identifier = $authenticator->getIdentifier();
125+
126+
$this->assertInstanceOf(\Authentication\Identifier\TokenIdentifier::class, $identifier);
127+
$this->assertSame('id', $identifier->getConfig('tokenField'));
128+
$this->assertSame('key', $identifier->getConfig('dataField'));
129+
}
130+
131+
/**
132+
* Test custom idField/identifierKey config propagates to default identifier
133+
*
134+
* @return void
135+
*/
136+
public function testGetIdentifierUsesCustomConfig()
137+
{
138+
$authenticator = new PrimaryKeySessionAuthenticator(null, [
139+
'idField' => 'uuid',
140+
'identifierKey' => 'token',
141+
]);
142+
$identifier = $authenticator->getIdentifier();
143+
144+
$this->assertInstanceOf(\Authentication\Identifier\TokenIdentifier::class, $identifier);
145+
$this->assertSame('uuid', $identifier->getConfig('tokenField'));
146+
$this->assertSame('token', $identifier->getConfig('dataField'));
147+
}
148+
92149
/**
93150
* Test authentication
94151
*

0 commit comments

Comments
 (0)