mirror of
https://github.com/delight-im/PHP-Auth.git
synced 2025-08-08 00:56:28 +02:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a1ae66374b | ||
|
477164e8ec | ||
|
9478a43e9b | ||
|
1ba8e1ff21 | ||
|
1657102f75 | ||
|
d246248ab5 | ||
|
94531f24d3 | ||
|
2f29830ed9 | ||
|
42a8c1616c | ||
|
a2be4c61ee | ||
|
d9f9198b45 | ||
|
13b58abebc | ||
|
b0bf7647ce | ||
|
012577227a | ||
|
d834623954 | ||
|
d3594898cc | ||
|
7d44158c32 | ||
|
04edd9f88f | ||
|
cd2ac47912 | ||
|
7bcf201972 | ||
|
09247e7203 | ||
|
ab1c54fae2 | ||
|
23acb66cc7 | ||
|
a7a9d45302 | ||
|
ba4dc29ca5 | ||
|
0a97f67515 | ||
|
7a94c6acef | ||
|
dbbbf1b193 |
14
Migration.md
14
Migration.md
@@ -10,21 +10,11 @@
|
||||
|
||||
## General
|
||||
|
||||
Update your version of this library via Composer [[?]](https://github.com/delight-im/Knowledge/blob/master/Composer%20(PHP).md):
|
||||
|
||||
```
|
||||
$ composer update delight-im/auth
|
||||
```
|
||||
|
||||
If you want to perform a major version upgrade (e.g. from version `1.x.x` to version `2.x.x`), the version constraints defined in your `composer.json` [[?]](https://github.com/delight-im/Knowledge/blob/master/Composer%20(PHP).md) may not allow this. In that case, just add the dependency again to overwrite it with the latest version (or optionally with a specified version):
|
||||
|
||||
```
|
||||
$ composer require delight-im/auth
|
||||
```
|
||||
Update your version of this library using Composer and its `composer update` or `composer require` commands [[?]](https://github.com/delight-im/Knowledge/blob/master/Composer%20(PHP).md#how-do-i-update-libraries-or-modules-within-my-application).
|
||||
|
||||
## From `v6.x.x` to `v7.x.x`
|
||||
|
||||
* The method `logOutButKeepSession` from class `Auth` is now simply called `logOut`. Therefore, the former method `logout` is now called `logOutAndDestroySession`. With both methods, mind the capitalization of the letter “O”.
|
||||
* The method `logOutButKeepSession` from class `Auth` is now simply called `logOut`. Therefore, the former method `logout` is now called `logOutAndDestroySession`.
|
||||
|
||||
* The second argument of the `Auth` constructor, which was named `$useHttps`, has been removed. If you previously had it set to `true`, make sure to set the value of the `session.cookie_secure` directive to `1` now. You may do so either directly in your [PHP configuration](http://php.net/manual/en/configuration.file.php) (`php.ini`), via the `\ini_set` method or via the `\session_set_cookie_params` method. Otherwise, make sure that directive is set to `0`.
|
||||
|
||||
|
59
README.md
59
README.md
@@ -109,10 +109,12 @@ $auth = new \Delight\Auth\Auth($db);
|
||||
|
||||
If you have an open `PDO` connection already, just re-use it.
|
||||
|
||||
If your web server is behind a proxy server and `$_SERVER['REMOTE_ADDR']` only contains the proxy’s IP address, you must pass the user’s real IP address to the constructor in the second argument, which is named `$ipAddress`. The default is `null`.
|
||||
If your web server is behind a proxy server and `$_SERVER['REMOTE_ADDR']` only contains the proxy’s IP address, you must pass the user’s real IP address to the constructor in the second argument, which is named `$ipAddress`. The default is the usual remote IP address received by PHP.
|
||||
|
||||
Should your database tables for this library need a common prefix, e.g. `my_users` instead of `users` (and likewise for the other tables), pass the prefix (e.g. `my_`) as the third parameter to the constructor, which is named `$dbTablePrefix`. This is optional and the prefix is empty by default.
|
||||
|
||||
During development, you may want to disable the request limiting or throttling performed by this library. To do so, pass `false` to the constructor as the fourth argument, which is named `$throttling`. The feature is enabled by default.
|
||||
|
||||
### Registration (sign up)
|
||||
|
||||
```php
|
||||
@@ -226,6 +228,8 @@ Omit the third parameter or set it to `null` to disable the feature. Otherwise,
|
||||
|
||||
### Password reset (“forgot password”)
|
||||
|
||||
#### Step 1 of 3: Initiating the request
|
||||
|
||||
```php
|
||||
try {
|
||||
$auth->forgotPassword($_POST['email'], function ($selector, $token) {
|
||||
@@ -254,12 +258,39 @@ You should build an URL with the selector and token and send it to the user, e.g
|
||||
$url = 'https://www.example.com/reset_password?selector=' . \urlencode($selector) . '&token=' . \urlencode($token);
|
||||
```
|
||||
|
||||
#### Step 2 of 3: Verifying an attempt
|
||||
|
||||
As the next step, users will click on the link that they received. Extract the selector and token from the URL.
|
||||
|
||||
If the selector/token pair is valid, let the user choose a new password:
|
||||
|
||||
```php
|
||||
if ($auth->canResetPassword($_POST['selector'], $_POST['token'])) {
|
||||
try {
|
||||
$auth->canResetPasswordOrThrow($_GET['selector'], $_GET['token']);
|
||||
|
||||
// put the selector into a `hidden` field (or keep it in the URL)
|
||||
// put the token into a `hidden` field (or keep it in the URL)
|
||||
|
||||
// ask the user for their new password
|
||||
}
|
||||
catch (\Delight\Auth\InvalidSelectorTokenPairException $e) {
|
||||
// invalid token
|
||||
}
|
||||
catch (\Delight\Auth\TokenExpiredException $e) {
|
||||
// token expired
|
||||
}
|
||||
catch (\Delight\Auth\ResetDisabledException $e) {
|
||||
// password reset is disabled
|
||||
}
|
||||
catch (\Delight\Auth\TooManyRequestsException $e) {
|
||||
// too many requests
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, if you don’t need any error messages but only want to check the validity, you can use the slightly simpler version:
|
||||
|
||||
```php
|
||||
if ($auth->canResetPassword($_GET['selector'], $_GET['token'])) {
|
||||
// put the selector into a `hidden` field (or keep it in the URL)
|
||||
// put the token into a `hidden` field (or keep it in the URL)
|
||||
|
||||
@@ -267,6 +298,8 @@ if ($auth->canResetPassword($_POST['selector'], $_POST['token'])) {
|
||||
}
|
||||
```
|
||||
|
||||
#### Step 3 of 3: Updating the password
|
||||
|
||||
Now when you have the new password for the user (and still have the other two pieces of information), you can reset the password:
|
||||
|
||||
```php
|
||||
@@ -581,6 +614,12 @@ if ($auth->hasAllRoles(\Delight\Auth\Role::DEVELOPER, \Delight\Auth\Role::MANAGE
|
||||
|
||||
While the method `hasRole` takes exactly one role as its argument, the two methods `hasAnyRole` and `hasAllRoles` can take any number of roles that you would like to check for.
|
||||
|
||||
Alternatively, you can get a list of all the roles that have been assigned to the user:
|
||||
|
||||
```php
|
||||
$auth->getRoles();
|
||||
```
|
||||
|
||||
#### Available roles
|
||||
|
||||
```php
|
||||
@@ -608,7 +647,15 @@ While the method `hasRole` takes exactly one role as its argument, the two metho
|
||||
\Delight\Auth\Role::TRANSLATOR;
|
||||
```
|
||||
|
||||
You can use any of these roles and ignore those that you don’t need.
|
||||
You can use any of these roles and ignore those that you don’t need. The list above can also be retrieved programmatically, in one of three formats:
|
||||
|
||||
```php
|
||||
\Delight\Auth\Role::getMap();
|
||||
// or
|
||||
\Delight\Auth\Role::getNames();
|
||||
// or
|
||||
\Delight\Auth\Role::getValues();
|
||||
```
|
||||
|
||||
#### Permissions (or access rights, privileges or capabilities)
|
||||
|
||||
@@ -899,6 +946,12 @@ catch (\Delight\Auth\UnknownIdException $e) {
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, you can get a list of all the roles that have been assigned to the user:
|
||||
|
||||
```php
|
||||
$auth->admin()->getRolesForUserById($userId);
|
||||
```
|
||||
|
||||
#### Impersonating users (logging in as user)
|
||||
|
||||
```php
|
||||
|
@@ -286,6 +286,36 @@ final class Administration extends UserManager {
|
||||
return ($rolesBitmask & $role) === $role;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the roles of the user with the given ID, mapping the numerical values to their descriptive names
|
||||
*
|
||||
* @param int $userId the ID of the user to return the roles for
|
||||
* @return array
|
||||
* @throws UnknownIdException if no user with the specified ID has been found
|
||||
*
|
||||
* @see Role
|
||||
*/
|
||||
public function getRolesForUserById($userId) {
|
||||
$userId = (int) $userId;
|
||||
|
||||
$rolesBitmask = $this->db->selectValue(
|
||||
'SELECT roles_mask FROM ' . $this->dbTablePrefix . 'users WHERE id = ?',
|
||||
[ $userId ]
|
||||
);
|
||||
|
||||
if ($rolesBitmask === null) {
|
||||
throw new UnknownIdException();
|
||||
}
|
||||
|
||||
return \array_filter(
|
||||
Role::getMap(),
|
||||
function ($each) use ($rolesBitmask) {
|
||||
return ($rolesBitmask & $each) === $each;
|
||||
},
|
||||
\ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signs in as the user with the specified ID
|
||||
*
|
||||
|
80
src/Auth.php
80
src/Auth.php
@@ -26,6 +26,8 @@ final class Auth extends UserManager {
|
||||
|
||||
/** @var string the user's current IP address */
|
||||
private $ipAddress;
|
||||
/** @var bool whether throttling should be enabled (e.g. in production) or disabled (e.g. during development) */
|
||||
private $throttling;
|
||||
/** @var string the name of the cookie used for the 'remember me' feature */
|
||||
private $rememberCookieName;
|
||||
|
||||
@@ -33,11 +35,13 @@ final class Auth extends UserManager {
|
||||
* @param PdoDatabase|PdoDsn|\PDO $databaseConnection the database connection to operate on
|
||||
* @param string $ipAddress the IP address that should be used instead of the default setting (if any), e.g. when behind a proxy
|
||||
* @param string|null $dbTablePrefix (optional) the prefix for the names of all database tables used by this component
|
||||
* @param bool|null $throttling (optional) whether throttling should be enabled (e.g. in production) or disabled (e.g. during development)
|
||||
*/
|
||||
public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null) {
|
||||
public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null, $throttling = null) {
|
||||
parent::__construct($databaseConnection, $dbTablePrefix);
|
||||
|
||||
$this->ipAddress = !empty($ipAddress) ? $ipAddress : (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null);
|
||||
$this->throttling = isset($throttling) ? (bool) $throttling : true;
|
||||
$this->rememberCookieName = self::createRememberCookieName();
|
||||
|
||||
$this->initSession();
|
||||
@@ -568,6 +572,7 @@ final class Auth extends UserManager {
|
||||
}
|
||||
}
|
||||
|
||||
// consume the token just being used for confirmation
|
||||
try {
|
||||
$this->db->delete(
|
||||
$this->dbTablePrefix . 'users_confirmations',
|
||||
@@ -752,8 +757,8 @@ final class Auth extends UserManager {
|
||||
throw new EmailNotVerifiedException();
|
||||
}
|
||||
|
||||
$this->throttle([ 'requestEmailChange', 'userId', $this->getUserId() ], 1, (60 * 60 * 24));
|
||||
$this->throttle([ 'requestEmailChange', $this->getIpAddress() ], 1, (60 * 60 * 24), 3);
|
||||
$this->throttle([ 'requestEmailChange', 'user', $this->getUserId() ], 1, (60 * 60 * 24), 3);
|
||||
|
||||
$this->createConfirmationRequest($this->getUserId(), $newEmail, $callback);
|
||||
}
|
||||
@@ -827,7 +832,7 @@ final class Auth extends UserManager {
|
||||
private function resendConfirmationForColumnValue($columnName, $columnValue, callable $callback) {
|
||||
try {
|
||||
$latestAttempt = $this->db->selectRow(
|
||||
'SELECT user_id, email, expires FROM ' . $this->dbTablePrefix . 'users_confirmations WHERE ' . $columnName . ' = ? ORDER BY id DESC LIMIT 1 OFFSET 0',
|
||||
'SELECT user_id, email FROM ' . $this->dbTablePrefix . 'users_confirmations WHERE ' . $columnName . ' = ? ORDER BY id DESC LIMIT 1 OFFSET 0',
|
||||
[ $columnValue ]
|
||||
);
|
||||
}
|
||||
@@ -839,14 +844,8 @@ final class Auth extends UserManager {
|
||||
throw new ConfirmationRequestNotFound();
|
||||
}
|
||||
|
||||
$retryAt = $latestAttempt['expires'] - 0.75 * self::CONFIRMATION_REQUESTS_TTL_IN_SECONDS;
|
||||
|
||||
if ($retryAt > \time()) {
|
||||
throw new TooManyRequestsException('', $retryAt - \time());
|
||||
}
|
||||
|
||||
$this->throttle([ 'resendConfirmation', 'userId', $latestAttempt['user_id'] ], 1, (60 * 60 * 6));
|
||||
$this->throttle([ 'resendConfirmation', $this->getIpAddress() ], 4, (60 * 60 * 24 * 7), 2);
|
||||
$this->throttle([ 'resendConfirmation', 'user', $latestAttempt['user_id'] ], 4, (60 * 60 * 24 * 7), 2);
|
||||
|
||||
$this->createConfirmationRequest(
|
||||
$latestAttempt['user_id'],
|
||||
@@ -1205,6 +1204,40 @@ final class Auth extends UserManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the supplied selector/token pair can be used to reset a password
|
||||
*
|
||||
* The password can be reset using the supplied information if this method does *not* throw any exception
|
||||
*
|
||||
* The selector/token pair must have been generated previously by calling `Auth#forgotPassword(...)`
|
||||
*
|
||||
* @param string $selector the selector from the selector/token pair
|
||||
* @param string $token the token from the selector/token pair
|
||||
* @throws InvalidSelectorTokenPairException if either the selector or the token was not correct
|
||||
* @throws TokenExpiredException if the token has already expired
|
||||
* @throws ResetDisabledException if the user has explicitly disabled password resets for their account
|
||||
* @throws TooManyRequestsException if the number of allowed attempts/requests has been exceeded
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
public function canResetPasswordOrThrow($selector, $token) {
|
||||
try {
|
||||
// pass an invalid password intentionally to force an expected error
|
||||
$this->resetPassword($selector, $token, null);
|
||||
|
||||
// we should already be in one of the `catch` blocks now so this is not expected
|
||||
throw new AuthError();
|
||||
}
|
||||
// if the password is the only thing that's invalid
|
||||
catch (InvalidPasswordException $ignored) {
|
||||
// the password can be reset
|
||||
}
|
||||
// if some other things failed (as well)
|
||||
catch (AuthException $e) {
|
||||
// re-throw the exception
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the supplied selector/token pair can be used to reset a password
|
||||
*
|
||||
@@ -1217,18 +1250,10 @@ final class Auth extends UserManager {
|
||||
*/
|
||||
public function canResetPassword($selector, $token) {
|
||||
try {
|
||||
// pass an invalid password intentionally to force an expected error
|
||||
$this->resetPassword($selector, $token, null);
|
||||
$this->canResetPasswordOrThrow($selector, $token);
|
||||
|
||||
// we should already be in the `catch` block now so this is not expected
|
||||
throw new AuthError();
|
||||
}
|
||||
// if the password is the only thing that's invalid
|
||||
catch (InvalidPasswordException $e) {
|
||||
// the password can be reset
|
||||
return true;
|
||||
}
|
||||
// if some other things failed (as well)
|
||||
catch (AuthException $e) {
|
||||
return false;
|
||||
}
|
||||
@@ -1501,6 +1526,19 @@ final class Auth extends UserManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the user's roles, mapping the numerical values to their descriptive names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRoles() {
|
||||
return \array_filter(
|
||||
Role::getMap(),
|
||||
[ $this, 'hasRole' ],
|
||||
\ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the currently signed-in user has been remembered by a long-lived cookie
|
||||
*
|
||||
@@ -1538,6 +1576,10 @@ final class Auth extends UserManager {
|
||||
* @throws AuthError if an internal problem occurred (do *not* catch)
|
||||
*/
|
||||
public function throttle(array $criteria, $supply, $interval, $burstiness = null, $simulated = null, $cost = null) {
|
||||
if (!$this->throttling) {
|
||||
return $supply;
|
||||
}
|
||||
|
||||
// generate a unique key for the bucket (consisting of 44 or fewer ASCII characters)
|
||||
$key = Base64::encodeUrlSafeWithoutPadding(
|
||||
\hash(
|
||||
|
49
src/Role.php
49
src/Role.php
@@ -32,14 +32,47 @@ final class Role {
|
||||
const SUPER_EDITOR = 524288;
|
||||
const SUPER_MODERATOR = 1048576;
|
||||
const TRANSLATOR = 2097152;
|
||||
// const XXX = 4194304;
|
||||
// const XXX = 8388608;
|
||||
// const XXX = 16777216;
|
||||
// const XXX = 33554432;
|
||||
// const XXX = 67108864;
|
||||
// const XXX = 134217728;
|
||||
// const XXX = 268435456;
|
||||
// const XXX = 536870912;
|
||||
// const XYZ = 4194304;
|
||||
// const XYZ = 8388608;
|
||||
// const XYZ = 16777216;
|
||||
// const XYZ = 33554432;
|
||||
// const XYZ = 67108864;
|
||||
// const XYZ = 134217728;
|
||||
// const XYZ = 268435456;
|
||||
// const XYZ = 536870912;
|
||||
|
||||
/**
|
||||
* Returns an array mapping the numerical role values to their descriptive names
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getMap() {
|
||||
$reflectionClass = new \ReflectionClass(static::class);
|
||||
|
||||
return \array_flip($reflectionClass->getConstants());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptive role names
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getNames() {
|
||||
$reflectionClass = new \ReflectionClass(static::class);
|
||||
|
||||
return \array_keys($reflectionClass->getConstants());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the numerical role values
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public static function getValues() {
|
||||
$reflectionClass = new \ReflectionClass(static::class);
|
||||
|
||||
return \array_values($reflectionClass->getConstants());
|
||||
}
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
|
@@ -38,7 +38,6 @@ abstract class UserManager {
|
||||
const SESSION_FIELD_ROLES = 'auth_roles';
|
||||
/** @var string session field for whether the user who is currently signed in (if any) has been remembered (instead of them having authenticated actively) */
|
||||
const SESSION_FIELD_REMEMBERED = 'auth_remembered';
|
||||
const CONFIRMATION_REQUESTS_TTL_IN_SECONDS = 60 * 60 * 24;
|
||||
|
||||
/** @var PdoDatabase the database connection to operate on */
|
||||
protected $db;
|
||||
@@ -308,9 +307,7 @@ abstract class UserManager {
|
||||
$selector = self::createRandomString(16);
|
||||
$token = self::createRandomString(16);
|
||||
$tokenHashed = \password_hash($token, \PASSWORD_DEFAULT);
|
||||
|
||||
// the request shall be valid for one day
|
||||
$expires = \time() + self::CONFIRMATION_REQUESTS_TTL_IN_SECONDS;
|
||||
$expires = \time() + 60 * 60 * 24;
|
||||
|
||||
try {
|
||||
$this->db->insert(
|
||||
|
@@ -245,7 +245,7 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
return 'email address not verified';
|
||||
}
|
||||
catch (\Delight\Auth\ResetDisabledException $e) {
|
||||
return 'password reset disabled';
|
||||
return 'password reset is disabled';
|
||||
}
|
||||
catch (\Delight\Auth\TooManyRequestsException $e) {
|
||||
return 'too many requests';
|
||||
@@ -264,7 +264,7 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
return 'token expired';
|
||||
}
|
||||
catch (\Delight\Auth\ResetDisabledException $e) {
|
||||
return 'password reset disabled';
|
||||
return 'password reset is disabled';
|
||||
}
|
||||
catch (\Delight\Auth\InvalidPasswordException $e) {
|
||||
return 'invalid password';
|
||||
@@ -273,6 +273,25 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
return 'too many requests';
|
||||
}
|
||||
}
|
||||
else if ($_POST['action'] === 'canResetPassword') {
|
||||
try {
|
||||
$auth->canResetPasswordOrThrow($_POST['selector'], $_POST['token']);
|
||||
|
||||
return 'yes';
|
||||
}
|
||||
catch (\Delight\Auth\InvalidSelectorTokenPairException $e) {
|
||||
return 'invalid token';
|
||||
}
|
||||
catch (\Delight\Auth\TokenExpiredException $e) {
|
||||
return 'token expired';
|
||||
}
|
||||
catch (\Delight\Auth\ResetDisabledException $e) {
|
||||
return 'password reset is disabled';
|
||||
}
|
||||
catch (\Delight\Auth\TooManyRequestsException $e) {
|
||||
return 'too many requests';
|
||||
}
|
||||
}
|
||||
else if ($_POST['action'] === 'reconfirmPassword') {
|
||||
try {
|
||||
return $auth->reconfirmPassword($_POST['password']) ? 'correct' : 'wrong';
|
||||
@@ -523,6 +542,19 @@ function processRequestData(\Delight\Auth\Auth $auth) {
|
||||
return 'ID required';
|
||||
}
|
||||
}
|
||||
else if ($_POST['action'] === 'admin.getRoles') {
|
||||
if (isset($_POST['id'])) {
|
||||
try {
|
||||
return $auth->admin()->getRolesForUserById($_POST['id']);
|
||||
}
|
||||
catch (\Delight\Auth\UnknownIdException $e) {
|
||||
return 'unknown ID';
|
||||
}
|
||||
}
|
||||
else {
|
||||
return 'ID required';
|
||||
}
|
||||
}
|
||||
else if ($_POST['action'] === 'admin.logInAsUserById') {
|
||||
if (isset($_POST['id'])) {
|
||||
try {
|
||||
@@ -631,6 +663,9 @@ function showDebugData(\Delight\Auth\Auth $auth, $result) {
|
||||
echo 'Roles (developer *and* manager)' . "\t\t";
|
||||
\var_dump($auth->hasAllRoles(\Delight\Auth\Role::DEVELOPER, \Delight\Auth\Role::MANAGER));
|
||||
|
||||
echo 'Roles' . "\t\t\t\t\t";
|
||||
echo \json_encode($auth->getRoles()) . "\n";
|
||||
|
||||
echo "\n";
|
||||
|
||||
echo '$auth->isRemembered()' . "\t\t\t";
|
||||
@@ -796,6 +831,13 @@ function showGuestUserForm() {
|
||||
echo '<button type="submit">Reset password</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="canResetPassword" />';
|
||||
echo '<input type="text" name="selector" placeholder="Selector" /> ';
|
||||
echo '<input type="text" name="token" placeholder="Token" /> ';
|
||||
echo '<button type="submit">Can reset password?</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<h1>Administration</h1>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
@@ -877,6 +919,12 @@ function showGuestUserForm() {
|
||||
echo '<button type="submit">Does user have role?</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.getRoles" />';
|
||||
echo '<input type="text" name="id" placeholder="ID" /> ';
|
||||
echo '<button type="submit">Get user\'s roles</button>';
|
||||
echo '</form>';
|
||||
|
||||
echo '<form action="" method="post" accept-charset="utf-8">';
|
||||
echo '<input type="hidden" name="action" value="admin.logInAsUserById" />';
|
||||
echo '<input type="text" name="id" placeholder="ID" /> ';
|
||||
@@ -923,11 +971,9 @@ function showConfirmEmailForm() {
|
||||
}
|
||||
|
||||
function createRolesOptions() {
|
||||
$roleReflection = new ReflectionClass(\Delight\Auth\Role::class);
|
||||
|
||||
$out = '';
|
||||
|
||||
foreach ($roleReflection->getConstants() as $roleName => $roleValue) {
|
||||
foreach (\Delight\Auth\Role::getMap() as $roleValue => $roleName) {
|
||||
$out .= '<option value="' . $roleValue . '">' . $roleName . '</option>';
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user