• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / security / 22292290616

23 Feb 2026 03:52AM UTC coverage: 92.466%. Remained the same
22292290616

push

github

dg
added CLAUDE.md

540 of 584 relevant lines covered (92.47%)

0.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.77
/src/Security/User.php
1
<?php declare(strict_types=1);
1✔
2

3
/**
4
 * This file is part of the Nette Framework (https://nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Nette\Security;
9

10
use Nette;
11
use Nette\Utils\Arrays;
12
use function func_get_args;
13

14

15
/**
16
 * User authentication and authorization.
17
 *
18
 * @property-read bool $loggedIn
19
 * @property-read ?IIdentity $identity
20
 * @property-read string|int|null $id
21
 * @property-read string[] $roles
22
 * @property-read ?int $logoutReason
23
 * @property   IAuthenticator $authenticator
24
 * @property   Authorizator $authorizator
25
 */
26
class User
27
{
28
        use Nette\SmartObject;
29

30
        /** Log-out reason */
31
        public const
32
                LogoutManual = 1,
33
                LogoutInactivity = 2;
34

35
        /** @deprecated use User::LogoutManual */
36
        public const LOGOUT_MANUAL = self::LogoutManual;
37

38
        /** @deprecated use User::LogoutManual */
39
        public const MANUAL = self::LogoutManual;
40

41
        /** @deprecated use User::LogoutInactivity */
42
        public const LOGOUT_INACTIVITY = self::LogoutInactivity;
43

44
        /** @deprecated use User::LogoutInactivity */
45
        public const INACTIVITY = self::LogoutInactivity;
46

47
        /** default role for unauthenticated user */
48
        public string $guestRole = 'guest';
49

50
        /** default role for authenticated user without own identity */
51
        public string $authenticatedRole = 'authenticated';
52

53
        /** @var array<callable(self): void>  Occurs when the user is successfully logged in */
54
        public array $onLoggedIn = [];
55

56
        /** @var array<callable(self): void>  Occurs when the user is logged out */
57
        public array $onLoggedOut = [];
58

59
        private ?IIdentity $identity = null;
60
        private ?bool $authenticated = null;
61
        private ?int $logoutReason = null;
62

63

64
        public function __construct(
1✔
65
                private UserStorage $storage,
66
                private ?IAuthenticator $authenticator = null,
67
                private ?Authorizator $authorizator = null,
68
        ) {
69
        }
1✔
70

71

72
        final public function getStorage(): UserStorage
73
        {
74
                return $this->storage;
×
75
        }
76

77

78
        /********************* Authentication ****************d*g**/
79

80

81
        /**
82
         * Conducts the authentication process. Parameters are optional.
83
         * @param  string|IIdentity  $username  name or Identity
84
         * @throws AuthenticationException if authentication was not successful
85
         */
86
        public function login(
1✔
87
                string|IIdentity $username,
88
                #[\SensitiveParameter]
89
                ?string $password = null,
90
        ): void
91
        {
92
                $this->logout(clearIdentity: true);
1✔
93
                if ($username instanceof IIdentity) {
1✔
94
                        $this->identity = $username;
1✔
95
                } else {
96
                        $authenticator = $this->getAuthenticator();
1✔
97
                        $this->identity = $authenticator instanceof Authenticator
1✔
98
                                ? $authenticator->authenticate(...func_get_args())
1✔
99
                                : $authenticator->authenticate(func_get_args());
×
100
                }
101

102
                $id = $this->authenticator instanceof IdentityHandler
1✔
103
                        ? $this->authenticator->sleepIdentity($this->identity)
1✔
104
                        : $this->identity;
1✔
105

106
                $this->storage->saveAuthentication($id);
1✔
107
                $this->authenticated = true;
1✔
108
                $this->logoutReason = null;
1✔
109
                Arrays::invoke($this->onLoggedIn, $this);
1✔
110
        }
1✔
111

112

113
        /**
114
         * Logs out the user from the current session.
115
         */
116
        final public function logout(bool $clearIdentity = false): void
1✔
117
        {
118
                $logged = $this->isLoggedIn();
1✔
119
                $this->storage->clearAuthentication($clearIdentity);
1✔
120
                $this->authenticated = false;
1✔
121
                $this->logoutReason = self::LogoutManual;
1✔
122
                if ($logged) {
1✔
123
                        Arrays::invoke($this->onLoggedOut, $this);
1✔
124
                }
125

126
                $this->identity = $clearIdentity ? null : $this->identity;
1✔
127
        }
1✔
128

129

130
        /**
131
         * Is this user authenticated?
132
         */
133
        final public function isLoggedIn(): bool
134
        {
135
                if ($this->authenticated === null) {
1✔
136
                        $this->getStoredData();
1✔
137
                }
138

139
                return (bool) $this->authenticated;
1✔
140
        }
141

142

143
        /**
144
         * Returns current user identity, if any.
145
         */
146
        final public function getIdentity(): ?IIdentity
147
        {
148
                if ($this->authenticated === null) {
1✔
149
                        $this->getStoredData();
1✔
150
                }
151

152
                return $this->identity;
1✔
153
        }
154

155

156
        private function getStoredData(): void
157
        {
158
                (function (bool $state, ?IIdentity $id, ?int $reason) use (&$identity) {
1✔
159
                        $identity = $id;
1✔
160
                        $this->authenticated = $state;
1✔
161
                        $this->logoutReason = $reason;
1✔
162
                })(...$this->storage->getState());
1✔
163

164
                $this->identity = $identity && $this->authenticator instanceof IdentityHandler
1✔
165
                        ? $this->authenticator->wakeupIdentity($identity)
1✔
166
                        : $identity;
1✔
167
                $this->authenticated = $this->authenticated && $this->identity !== null;
1✔
168
        }
1✔
169

170

171
        /**
172
         * Returns current user ID, if any.
173
         */
174
        public function getId(): string|int|null
175
        {
176
                $identity = $this->getIdentity();
1✔
177
                return $identity ? $identity->getId() : null;
1✔
178
        }
179

180

181
        final public function refreshStorage(): void
182
        {
183
                $this->identity = $this->authenticated = $this->logoutReason = null;
1✔
184
        }
1✔
185

186

187
        /**
188
         * Sets authentication handler.
189
         */
190
        public function setAuthenticator(IAuthenticator $handler): static
1✔
191
        {
192
                $this->authenticator = $handler;
1✔
193
                return $this;
1✔
194
        }
195

196

197
        /**
198
         * Returns authentication handler.
199
         */
200
        final public function getAuthenticator(): IAuthenticator
201
        {
202
                if (!$this->authenticator) {
1✔
203
                        throw new Nette\InvalidStateException('Authenticator has not been set.');
1✔
204
                }
205

206
                return $this->authenticator;
1✔
207
        }
208

209

210
        /**
211
         * Returns authentication handler.
212
         */
213
        final public function getAuthenticatorIfExists(): ?IAuthenticator
214
        {
215
                return $this->authenticator;
×
216
        }
217

218

219
        /** @deprecated */
220
        final public function hasAuthenticator(): bool
221
        {
222
                return (bool) $this->authenticator;
×
223
        }
224

225

226
        /**
227
         * Enables log out after inactivity (like '20 minutes').
228
         */
229
        public function setExpiration(?string $expire, bool $clearIdentity = false): static
1✔
230
        {
231
                $this->storage->setExpiration($expire, $clearIdentity);
1✔
232
                return $this;
1✔
233
        }
234

235

236
        /**
237
         * Why was user logged out? Returns LOGOUT_MANUAL or LOGOUT_INACTIVITY.
238
         */
239
        final public function getLogoutReason(): ?int
240
        {
241
                return $this->logoutReason;
1✔
242
        }
243

244

245
        /********************* Authorization ****************d*g**/
246

247

248
        /**
249
         * Returns a list of effective roles that a user has been granted.
250
         * @return string[]
251
         */
252
        public function getRoles(): array
253
        {
254
                if (!$this->isLoggedIn()) {
1✔
255
                        return [$this->guestRole];
1✔
256
                }
257

258
                $identity = $this->getIdentity();
1✔
259
                return $identity?->getRoles() ?? [$this->authenticatedRole];
1✔
260
        }
261

262

263
        /**
264
         * Is a user in the specified effective role?
265
         */
266
        final public function isInRole(string $role): bool
1✔
267
        {
268
                foreach ($this->getRoles() as $r) {
1✔
269
                        if ($role === ($r instanceof Role ? $r->getRoleId() : $r)) {
1✔
270
                                return true;
1✔
271
                        }
272
                }
273

274
                return false;
1✔
275
        }
276

277

278
        /**
279
         * Has a user effective access to the Resource?
280
         * If $resource is null, then the query applies to all resources.
281
         */
282
        public function isAllowed(mixed $resource = Authorizator::All, mixed $privilege = Authorizator::All): bool
1✔
283
        {
284
                foreach ($this->getRoles() as $role) {
1✔
285
                        if ($this->getAuthorizator()->isAllowed($role, $resource, $privilege)) {
1✔
286
                                return true;
1✔
287
                        }
288
                }
289

290
                return false;
1✔
291
        }
292

293

294
        /**
295
         * Sets authorization handler.
296
         */
297
        public function setAuthorizator(Authorizator $handler): static
1✔
298
        {
299
                $this->authorizator = $handler;
1✔
300
                return $this;
1✔
301
        }
302

303

304
        /**
305
         * Returns current authorization handler.
306
         */
307
        final public function getAuthorizator(): Authorizator
308
        {
309
                if (!$this->authorizator) {
1✔
310
                        throw new Nette\InvalidStateException('Authorizator has not been set.');
1✔
311
                }
312

313
                return $this->authorizator;
1✔
314
        }
315

316

317
        /**
318
         * Returns current authorization handler.
319
         */
320
        final public function getAuthorizatorIfExists(): ?Authorizator
321
        {
322
                return $this->authorizator;
×
323
        }
324

325

326
        /** @deprecated */
327
        final public function hasAuthorizator(): bool
328
        {
329
                return (bool) $this->authorizator;
×
330
        }
331
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc