diff options
Diffstat (limited to 'core/classes/authentication')
| -rw-r--r-- | core/classes/authentication/Core/PasswordTrait.php | 38 | ||||
| -rw-r--r-- | core/classes/authentication/Core/UserManager.php | 101 | ||||
| -rw-r--r-- | core/classes/authentication/Core/UserManagerInterface.php | 25 | ||||
| -rw-r--r-- | core/classes/authentication/Token/UserToken.php | 44 | ||||
| -rw-r--r-- | core/classes/authentication/Token/UserTokenInterface.php | 18 | ||||
| -rw-r--r-- | core/classes/authentication/User.php | 116 | ||||
| -rw-r--r-- | core/classes/authentication/UserInterface.php | 19 | ||||
| -rw-r--r-- | core/classes/authentication/info.md | 114 |
8 files changed, 475 insertions, 0 deletions
diff --git a/core/classes/authentication/Core/PasswordTrait.php b/core/classes/authentication/Core/PasswordTrait.php new file mode 100644 index 0000000..40a7381 --- /dev/null +++ b/core/classes/authentication/Core/PasswordTrait.php @@ -0,0 +1,38 @@ +<?php +/** Trait PasswordTrait + * + * @package DevCoder\Authentication\Core + * + */ +# namespace DevCoder\Authentication\Core; +# +# use DevCoder\Authentication\UserInterface; + +trait PasswordTrait +{ + + private $cost = 10; // Cost must be in the range of 4-31 + // a cost value in the range of 8-11 + // is a good balance between performance and security + + + public function cryptPassword(string $plainPassword): string + { + return password_hash($plainPassword, PASSWORD_BCRYPT, ['cost' => $this->cost]); + } + + + public function isPasswordValid(UserInterface $user, string $plainPassword): bool + { + return password_verify($plainPassword, $user->getPassword()); + } + + + public function setCost(int $cost): void + { + if ($cost < 4 || $cost > 31) { + throw new \InvalidArgumentException('Cost must be in the range of 4-31.'); + } + $this->cost = $cost; + } +} diff --git a/core/classes/authentication/Core/UserManager.php b/core/classes/authentication/Core/UserManager.php new file mode 100644 index 0000000..54cd2cb --- /dev/null +++ b/core/classes/authentication/Core/UserManager.php @@ -0,0 +1,101 @@ +<?php +/** Class UserManager + * + * @package DevCoder\Authentication\Core + * + */ +# namespace DevCoder\Authentication\Core; +# +# use DevCoder\Authentication\Token\UserToken; +# use DevCoder\Authentication\Token\UserTokenInterface; +# use DevCoder\Authentication\UserInterface; + +class UserManager implements UserManagerInterface +{ + + use PasswordTrait; + + + public function __construct() + { + if (session_status() === PHP_SESSION_NONE) { + session_start(); + } + } + + + /** getUserToken() + * == get user from session + * + */ + public function getUserToken(): ?UserTokenInterface + { + $userToken = null; + if ($this->hasUserToken()) { + $userToken = unserialize($_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY]); + } + + return $userToken; + } + + + /** hasUserToken() + * == is user loged in + * + */ + public function hasUserToken(): bool + { + $key = UserTokenInterface::DEFAULT_PREFIX_KEY; + return (array_key_exists($key, $_SESSION) && unserialize($_SESSION[$key]) !== false); + } + + + /** isGranted + * + * checks if user is granded some role(s) + * from the array of roles that are passed + * + * ex. $token->isGranted(['editor', 'designer']) ... + * returns true if the user is editor or designer (or both) + * + */ + public function isGranted(array $roles): bool + { + // if (!is_null($userToken = $this->getUserToken())) { + if (is_null($userToken = $this->getUserToken())) { + return false; + } + + if ($userToken->getUser() instanceof UserInterface) { + return (!empty(array_intersect($roles, $userToken->getUser()->getRoles()))); + } + + return false; + } + + + /** createUserToken() + * == serializes user and stores it into session + * so $_SESSION[DEFAULT_PREFIX_KEY] has the serialized representaion of user + */ + public function createUserToken(UserInterface $user): UserTokenInterface + { + $userToken = new UserToken($user); + $_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY] = $userToken->serialize(); + + return $userToken; + } + + + /** logout + * == clear session + * + */ + public function logout(): void + { + if ($this->hasUserToken()) { + unset($_SESSION[UserTokenInterface::DEFAULT_PREFIX_KEY]); + } + } + +} diff --git a/core/classes/authentication/Core/UserManagerInterface.php b/core/classes/authentication/Core/UserManagerInterface.php new file mode 100644 index 0000000..05110fb --- /dev/null +++ b/core/classes/authentication/Core/UserManagerInterface.php @@ -0,0 +1,25 @@ +<?php +/** Interface UserManagerInterface + * + * @package DevCoder\Authentication\Core + * + */ +# namespace DevCoder\Authentication\Core; +# +# use DevCoder\Authentication\Token\UserTokenInterface; +# use DevCoder\Authentication\UserInterface; + +interface UserManagerInterface +{ + public function getUserToken(): ?UserTokenInterface; + + public function hasUserToken(): bool; + + public function createUserToken(UserInterface $user): UserTokenInterface; + + public function logout(): void; + + public function cryptPassword(string $plainPassword): string; + + public function isPasswordValid(UserInterface $user, string $plainPassword): bool; +} diff --git a/core/classes/authentication/Token/UserToken.php b/core/classes/authentication/Token/UserToken.php new file mode 100644 index 0000000..b9bb024 --- /dev/null +++ b/core/classes/authentication/Token/UserToken.php @@ -0,0 +1,44 @@ +<?php +/** Class UserToken + * + * @package DevCoder\Authentication + * + */ +# namespace DevCoder\Authentication\Token; +# +# use DevCoder\Authentication\UserInterface; + +class UserToken implements UserTokenInterface +{ + /** + * @var UserInterface + */ + private $user; + + + public function __construct(UserInterface $user) + { + $this->user = $user; + } + + + /** getUser + * + */ + public function getUser(): UserInterface + { + return $this->user; + } + + + /** serialize() + * + * serializes the user structure (with user's property values) + * ... then it will be saved into session[DEFAULT_PREFIX_KEY] + * + */ + public function serialize(): string + { + return serialize($this); + } +} diff --git a/core/classes/authentication/Token/UserTokenInterface.php b/core/classes/authentication/Token/UserTokenInterface.php new file mode 100644 index 0000000..8e8b642 --- /dev/null +++ b/core/classes/authentication/Token/UserTokenInterface.php @@ -0,0 +1,18 @@ +<?php +/** Interface UserTokenInterface + * + * @package DevCoder\Authentication\Token + * + */ +# namespace DevCoder\Authentication\Token; +# +# use DevCoder\Authentication\UserInterface; + +interface UserTokenInterface +{ + const DEFAULT_PREFIX_KEY = 'user_security'; + + public function getUser(): UserInterface; + + public function serialize(): string; +} diff --git a/core/classes/authentication/User.php b/core/classes/authentication/User.php new file mode 100644 index 0000000..babc7fd --- /dev/null +++ b/core/classes/authentication/User.php @@ -0,0 +1,116 @@ +<?php +/** + * Class User + * + * based on + * @package DevCoder\Authentication + * + */ +# namespace DevCoder\Authentication; + +class User implements UserInterface +{ + + // @var string + private $userName; + + // @var string + private $password; + + // @var array + private $roles = []; + + // @var array + private $privileges = []; + + // @var bool + private $enabled = true; + + + + /** GETs + * ------------------------------------------------------------------------- + */ + + /** getUserName + * @return null|string + */ + public function getUsername(): ?string + { + return $this->userName; + } + + /** getPassword + * @return null|string + */ + public function getPassword(): ?string + { + return $this->password; + } + + /** getRoles + * @return array + */ + public function getRoles(): array + { + return $this->roles; + } + + /** isEnabled + * @return bool + */ + public function isEnabled(): bool + { + return $this->enabled; + } + + + /** SETs + * ------------------------------------------------------------------------- + */ + + /** setUserName() + * + * @param string $userName + * @return User + */ + public function setUserName(string $userName): self + { + $this->userName = $userName; + return $this; + } + + /** setPassword() + * + * @param string $password + * @return User + */ + public function setPassword(string $password): self + { + $this->password = $password; + return $this; + } + + /** setRoles() + * + * @param array $roles + * @return User + */ + public function setRoles(array $roles): self + { + $this->roles = $roles; + return $this; + } + + + /** setEnabled + * + * @param bool $enabled + * @return User + */ + public function setEnabled(bool $enabled): self + { + $this->enabled = $enabled; + return $this; + } +} diff --git a/core/classes/authentication/UserInterface.php b/core/classes/authentication/UserInterface.php new file mode 100644 index 0000000..b035215 --- /dev/null +++ b/core/classes/authentication/UserInterface.php @@ -0,0 +1,19 @@ +<?php +/** + * Interface UserInterface + * + * @package DevCoder\Authentication + * + */ +# namespace DevCoder\Authentication; + +interface UserInterface +{ + public function getUsername() :?string; + + public function getPassword() :?string; + + public function getRoles() : array; + + public function isEnabled(): bool; +}
\ No newline at end of file diff --git a/core/classes/authentication/info.md b/core/classes/authentication/info.md new file mode 100644 index 0000000..e6d1372 --- /dev/null +++ b/core/classes/authentication/info.md @@ -0,0 +1,114 @@ +# Authentication System + +read/ref: https://dev.to/fadymr/php-create-your-own-php-authentication-4e20 + +also for session: https://dev.to/fadymr/php-create-a-simple-session-wrapper-class-dpk + + + +## How to use ? + + +### Registration + + + // use DevCoder\Authentication\Core\UserManager; + // use DevCoder\Authentication\User; + + // register + $userManager = new UserManager(); + $req = Registry::get('REQUEST); + + $password = $userManager->cryptPassword($req->POST['password']); + + $user = (new User()) + ->setUserName($req->POST['username']) + ->setPassword($password) + ->setRoles(['ROLE_USER']); + + $userManager->createUserToken($user); + + // check Token in Session + var_dump($userManager->getUserToken()); + // object(DevCoder\Authentication\Token\UserToken)[4] + // private 'user' => + // object(DevCoder\Authentication\User)[5] + // private 'userName' => string 'username' (length=8) + // private 'password' => string '$2y$10$iWdcmebmikUFlgKMqW7/rOmUp1DjFAuWKqdUHBhL08FZ7LL6bwRey' (length=60) + // private 'roles' => + // array (size=1) + // 0 => string 'ROLE_USER' (length=9) + // private 'enabled' => boolean true + + +## Connected or not + + <?php + + // use DevCoder\Authentication\Core\UserManager; + // use DevCoder\Authentication\User; + + $userManager = new UserManager(); + if ($userManager->hasUserToken()) { + // connected + + $token = $userManager->getUserToken(); + $user = $token->getUser(); + var_dump($user); + // object(DevCoder\Authentication\User)[5] + // private 'userName' => string 'username' (length=8) + // private 'password' => string '$2y$10$OBobeLhdvdiftuedlv1a6e4.qF6sCG/usq5WEV4E3uB.UiS1egv/m' (length=60) + // private 'roles' => + // array (size=1) + // 0 => string 'ROLE_USER' (length=9) + // private 'enabled' => boolean true + + } else { + // not connected + } + + +## Access management + + $userManager = new UserManager(); + if ($userManager->isGranted(['ROLE_ADMIN'])) { + //is admin + // return Response 200 + }else { + //is not admin + // return Response 403 + } + + Logout + + $userManager = new UserManager(); + $userManager->logout(); + + +## Login + + <?php + + use DevCoder\Authentication\Core\UserManager; + + $stmt = $pdo->prepare("SELECT * FROM users WHERE username=?"); + $stmt->execute([$_POST['username']]); + $userFromDataBase = $stmt->fetch(); + /** + * Hydration + */ + $user = (new \Test\DevCoder\Authentication\User()) + ->setUserName($userFromDataBase['username']) + ->setPassword($userFromDataBase['password']) + ->setRoles(json_decode($userFromDataBase['roles'])) + ->setEnabled($userFromDataBase['active']); + + $userManager = new UserManager(); + if ($userManager->isPasswordValid($user, $_POST['password'])) { + + // login OK, set Token in session + $userManager->createUserToken($user); + + } else { + // login failed , return error + } |
