Download the PHP package odevnet/dulceauth without Composer
On this page you can find all versions of the php package odevnet/dulceauth. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download odevnet/dulceauth
More information about odevnet/dulceauth
Files in odevnet/dulceauth
Package dulceauth
Short Description PHP user management library that facilitates user registration and authentication, as well as the management of their roles and permissions. It is designed for small and medium-sized applications that require a robust, efficient and extensible solution.
License MIT
Homepage https://github.com/odevnet/dulceAuth/
Informations about the package dulceauth
What is "dulceAuth"?
DulceAuth is a PHP user management library that simplifies user registration and authentication, as well as the management of roles and permissions. It is designed for small to medium-sized applications that need a robust, efficient, and extensible solution.
Some features include:
- You can register one or multiple users at once.
- Controls access to different parts of the application by assigning roles and permissions.
- Integrates Laravel's "Eloquent ORM" to facilitate working with the database.
- Verifies user accounts by generating and validating tokens.
- Resets passwords.
- Supports easy email sending.
- Utilizes sessions and allows verification of user sessions.
- Captures and logs any errors that may occur.
- Easily extensible and customizable thanks to its modular architecture.
- Manages and facilitates dependency injection through the use of a "service container."
Table of Contents
- Installation and Usage
- Through GitHub
- Through Composer
- Library Usage
- Configuration
- Database
- Config.php
- JSON Files
- Exceptions
- Logger Class
- User Registration
- Account Verification
- Account Verification. Part Two.
- An Exceptional Case
- Login
- Users
- Does it Exist?
- Edit User
- Delete User
- Create Users
- Change Password
- Recover Password/Forgot Password
- Roles and Permissions
- Create a Role
- Edit a Role
- Delete a Role
- Assign Roles to Users
- Permissions
- Create a Permission
- Edit a Permission
- Delete a Permission
- Assign a Permission to a Role
- Remove a Permission from a Role
- Roles and Permissions. Part 2
- Authorization
- Sessions
- Session Duration
- Email Class
- Creating services
Claro, aquí está la traducción respetando el formato de markdown:
Installation and Usage
The only requirements are:
- MySQL database as a minimum (not tested on others)
- PHP version >= 8.2.0
Github
Open the command prompt (cmd) on Windows or the terminal of your operating system and navigate to the folder where you want to clone the repository:
For example, in the console, type:
cd path/to/your/directory
And then clone the repository by running in the console:
git clone https://github.com/odevnet/dulceAuth.git
Once cloned, with the console open and in the project directory, run:
composer install
to automatically install the necessary dependencies.
Composer
In a terminal and with composer installed, run the following command:
composer install odevnet/dulceauth
This will install the library and all necessary dependencies.
Usage
Once you have dulceAuth downloaded and configured, simply include and instantiate the library to use it like this:
And from here, you will be able to use each of the available methods provided by the library ;)
Configuration
Database
Use the following table structure for a MySQL database. These are the minimum required tables and fields. If you already have a users table, you will need to add the following fields: name, email, password, created_at, updated_at, verified, and visibility. For example, if your table is named "usuarios" and you already have a field called "username" for the user's name, you will need to rename that field to name and the table name to users. You should do the same for any other fields that differ.
Config File
The config file is quite descriptive regarding what each configuration option does and which ones we can modify and which ones we can't. For now, it's basic but functional. Create a file in src/config/config.php with all the following content, and for now, only edit the driver, host, database, username, and password. Also, adjust the constant WEB_PAGE and EMAIL_FROM. We'll leave the rest as it is.
JSON Files
The verification_email.json and forgot_password_email.json files should, by convention, be inside the /config folder. Copy the following content (modify it to your liking) to the verification_email.json file and save it to /config:
Same for the forgot_password_email.json file:
Exception Handling
Exceptions are organized by type, meaning whether they are related to roles, tokens, or users. For example, when registering a user, it might happen that a user with that email already exists. In this case, the exception that would be thrown is DuplicateEmailException, located in src\exceptions\users.
Below is a list of all possible exceptions:
Users:
-
src\exceptions\users\AccountValidationException -> See AccountValidationException
-
src\exceptions\users\ArrayOptionsUserException -> See ArrayOptionsUserException
-
src\exceptions\users\CreateUserException -> See CreateUserException
-
src\exceptions\users\DuplicateEmailException -> See DuplicateEmailException
-
src\exceptions\users\EditUserException -> See EditUserException
-
src\exceptions\users\InvalidPasswordException -> See InvalidPasswordException
-
src\exceptions\users\LimitChangesPasswordException -> See LimitChangesPasswordException
-
src\exceptions\users\RegisterException -> See RegisterException
-
src\exceptions\users\UserException -> See UserException
- src\exceptions\users\UserNotFoundException -> See UserNotFoundException
Tokens:
-
src\exceptions\tokens\RelationShipTokenException -> See RelationShipTokenException
-
src\exceptions\tokens\TokenException -> See TokenException
-
src\exceptions\tokens\TokenExpiredException -> See TokenExpiredException
-
src\exceptions\tokens\TokenNotFoundException -> See TokenNotFoundException
- src\exceptions\tokens\TokenSaveException -> See TokenSaveException
Roles and Permissions:
-
src\exceptions\roles\EmptyPermissionNameException -> See EmptyPermissionNameException
-
src\exceptions\roles\EmptyRoleNameException -> See EmptyRoleNameException
-
src\exceptions\roles\MissingRoleOrPermissionException -> See MissingRoleOrPermissionException
-
src\exceptions\roles\PermissionNotFoundException -> See PermissionNotFoundException
-
src\exceptions\roles\PermissionSaveException -> See PermissionSaveException
-
src\exceptions\roles\RoleAssignmentException -> See RoleAssignmentException
-
src\exceptions\roles\RoleNotAssignedException -> See RoleNotAssignedException
-
src\exceptions\roles\RoleNotFoundException -> See RoleNotFoundException
-
src\exceptions\roles\RoleNotSelectedException -> See RoleNotSelectedException
-
src\exceptions\roles\RolePermissionAlreadyExistsException -> See RolePermissionAlreadyExistsException
-
src\exceptions\roles\RolePermissionException -> See RolePermissionException
-
src\exceptions\roles\RoleSaveException -> See RoleSaveException
-
src\exceptions\roles\RolesException -> See RolesException
-
src\exceptions\roles\UsedPermissionNameException -> See UsedPermissionNameException
- src\exceptions\roles\UsedRoleNameException -> See UsedRoleNameException
As we explain the code, we will see when and how exceptions are used. In some cases, capturing exceptions will be necessary, while in others it will be optional. When registering a user, you should capture any exceptions that might occur; however, when a user "logs in," it is not necessary. In this latter case, it may be more advisable to display a more personalized message since the login method will return "true" or "false."
Keep in mind that each method can throw its own exceptions, but each method also has a general exception. For example, when creating a new role, you have the option to capture various exceptions that might occur, such as the role already being in use (UsedRoleNameException) or being empty (EmptyRoleNameException), etc. In this case, you can catch each of these specific exceptions individually, or you can "ignore" them and catch the general exception, which in this case would be RolesException.
For tokens and users, there is also a general exception for each case.
Logger Class
The Logger class is a simple class that allows you to log errors to a file to keep track of all errors or exceptions that have occurred. Every time we include a try-catch block, along with the exception, we should also include the Logger class:
This causes the exception to be recorded in the file. By default, this file is located at logs/log_file.log and can be modified through the LOG_FILE constant in the config file.
Register User
By default, and as a minimum, this method requires three fields: user, email, and password.
For example:
However, it can also accept a fourth parameter in the form of an associative array. The fourth parameter can be useful if you want to store additional data when registering a new user, such as country, address, phone number, etc. This is usually quite common.
You can do something like this:
This assumes that you have a field in the users table called country.
You might also want to modify the value of "verified". For example, if you want the newly created account to be created as verified, you should do it like this:
Or make the account visibility private:
Note: Each field you pass as the fourth additional parameter must exist in the 'users' table.
As you can see, the fourth parameter is quite useful if you want to pass or register several additional data points. Finally, regarding "registration," we have the option to register multiple users at once.
To do this, you could use a for loop like this:
Account Verification
We have seen that we have the option to create accounts as verified or unverified. Using the VERIFIED constant found in the config.php file, we can set whether all accounts should be created as verified or not upon registration.
But we can also do it at the time of registering an account, as mentioned above, by passing a fourth parameter to the register method.
Reminder:
1 means verified account.
0 means account pending verification. Email validation is required.
In the case where you want all accounts to require email validation, you will need to generate a random token for each new registration and send it to the newly registered user's email.
Don’t worry, the method will handle this for us. However, the register()
method will only send an email if the account requires verification; otherwise, it will not send anything. What I mean is, it could be useful to send another type of email to the user immediately after registration to thank them or inform them of their details, etc. But that’s better left for future versions.
Note:
If you pass the 'verified' option through the
register()
method, the 'VERIFIED' constant in the config will not be considered.
Account Verification. Part Two.
How do we verify an account?
It’s simple. Once the user has registered, the register
method sends an email to the user with a previously generated token. We need to validate it, and if everything is correct, verify the account.
The email the user will receive will contain a link similar to this:
So, in the part of your application, or in other words, on the page (verification.php) where you want to capture the data, i.e., the token and the user ID, you can use GET like this:
And validate them using two methods:
validateTokenAccount:
verified:
For example:
A more detailed example:
Or with a general exception:
Note: Both the email template sent to the user (i.e., the text sent to them) and the page where the token and user ID are received can be modified in the config file through the JSON_FILE_VERIFICATION_EMAIL and VERIFICATION_PAGE constants, respectively.
An Exceptional Case. Or Not!
It might happen that we require all users to verify their account upon registration, but what if an account remains pending verification for a long time? At the time of registration, a token would have been generated, but after X time, it would likely have expired. In this case, you should follow these steps:
Imagine a user has registered, an email was sent to verify the account, but for some reason, the user does not click the link until several days later. As expected, the token will have expired, and the link sent to their email will no longer work. In other words, a new link or, more precisely, a new token needs to be generated.
To do this, use the following method: generateVerificationToken(string $email, bool $send = true)
As seen, the second parameter $send is optional, and we can decide whether to pass it or not. If we execute the method without passing the second parameter, the method itself will send an email to the user so they can verify/validate their account.
If we execute the code above, we don’t need to do anything else. The user will receive an email with a link like:
and the procedure to follow will be exactly the same as described earlier in the section "Account Verification. Part Two.", using the verification.php file and capturing the necessary data, i.e., the token and user ID.
Now, if we call the generateVerificationToken
method with $send set to false, it will return an array containing the token and user ID.
By doing it this way, we can generate the email ourselves using the dulceMail class Read about this class.
For example:
After sending the email ourselves, we carry out the entire process: send the email, then capture the data (token and user ID), and use the validateTokenAccount
and verified
functions as before...
Login
$dulceAuth->login($email, $password);
This method connects a user to the system and creates their corresponding session.
Therefore, to log in a user, you would simply do:
If we want to check if the user is connected or if there is an active connection:
Clearer:
To logout, close, or end the session:
Once logged in, it may be useful to retrieve user data. To do this, we use the currentUser()
function followed by the fields we want to display.
For example:
If we have a field for the country called "country," we can do:
And similarly for each field we want to display for the currently logged-in user.
Users
There are several options for displaying a list of all users in the database.
For example, suppose we want to display a list of existing users but are only interested in showing their ID, name, email, and country. To do this, we can use the $dulceAuth->showUsers()
method and iterate through it with a foreach loop:
In addition to the powerful $dulceAuth->showUsers()
method, which we can use to iterate through any user-related fields we want to display, there are also the following three methods:
I think their names are quite descriptive for an explanation of what each one does ;-). We might think they are not useful, but who knows, if we ever need them, they are there!
Does the user exist?
If we want to check if a user exists, we have two ways to do it.
The first is through the userIdExists method:
This method will return true or false depending on whether the user ID we provided exists or not.
Another way to search for or determine if a user exists is by their email:
It will return true if the email exists, and false otherwise.
Editing Users
To edit a user, we use the *editUser*
method, which accepts two parameters: one is the user ID to be edited, and the other is an array of options with the new values.
Example:
In the previous example, we edited the name, email, and country fields for the user with ID 1. The return value will be true or false.
By the way, going back to the topic of exceptions, the previous code could be simplified to:
But I recommend specifying each exception ;-)
Deleting a User
To delete a user, simply execute the "deleteUser"
method, passing the user ID to be deleted.
It will return true or false upon success.
Creating a New User
It may be useful to create a new user without needing to use the "register"
method.
For example, if you have an admin panel and want the option to create users, you can use the "createUser"
method.
This method requires at least three parameters: name, email, and password. There is also an optional fourth parameter, which is an array that allows you to pass additional data to be registered, such as their phone number, country, etc.
Here’s an example using the optional fourth parameter. If we want the new account to be created as verified and with a phone number, we would do it like this:
Changing a User's Password
To change a user's password, you need to execute the "changePassword"
method with three parameters:
changePassword(int $userId, string $currentPassword, string $newPassword)
For example, to change the password of the user with ID '1':
dulceAuth allows you to set a limit on password changes, which by default is 3 changes per year. You can change this through the MAX_PASSWORD_CHANGES constant in the config.php file.
I think this can be useful to prevent abusive and unnecessary use of the changePassword
method.
It might also be helpful to know the total number of password changes made (if any) by a user. To do this:
The "latestChange"
method accepts one parameter, which is the user ID to query, and returns an instance of PasswordChange
if a password change is found. You can then use the changes_count property on it to find out the total number of changes.
Password Recovery
If a user has forgotten their password, since the password uses secure encryption, it is impossible to recover it, so a new one must be created. For this, dulceAuth will generate a temporary token so the user can create a new password.
Using the forgotPassword method:
forgotPassword($email, $send = true)
A token is generated for the user whose email has been provided as a parameter.
The $send
parameter is optional, and you can decide whether to include it or not. Whether you include it or not affects how the method behaves.
Basically, by default, this method sends an email to the user with a link containing the token and their user ID, which will later be used to create a new password.
This should sound familiar, as it works similarly to the generateVerificationToken
method.
The common way to use it is:
If we call the method with $send set to false, it will return an array containing the token and the user ID.
By doing it this way, we can generate the email sent to the user ourselves using the dulceMail class.
Let’s look at some examples.
Suppose the user named "Test" with the email "[email protected]" has forgotten their password.
In this case, we will call the forgotPassword
method only by passing the user's email, so that the method itself handles sending the email with the recovery link containing the token and user ID:
If we check the email and click on the link, it will take us to the page set as the "password recovery" page. The default page for password recovery is called forgot.php and is set with the constant FORGOT_PASSWORD_PAGE in the config.php file.
On this page, we retrieve the token and userId values using $_GET and pass them to the validateTokenPassword method:
validateTokenPassword(string $token, int $userId): bool
For example:
Finally, if the validation is correct, we create the new password using the insertNewPassword method:
insertNewPassword(string $password, int $userId): void
This method takes the new password and the user ID as parameters.
A more complete example might be the forgot.php page:
We have seen the recommended and straightforward way to do this. Now, let’s move on to the second method, which essentially involves sending/generating the recovery email ourselves using the dulceMail class. To do this, call the forgotPassword method, passing the user's email and setting the second parameter to false. In this way, it will only return the user ID and the temporary token that has been generated. The next step will be to generate the email ourselves to send to the user:
That’s it! From here on, the process is the same as before. After clicking on the link from the password recovery page, we retrieve the token and userId values and pass them to the validateTokenPassword method, and then call the insertNewPassword method.
Very Important:
The insertNewPassword method must be called after generating a token; otherwise, it will throw an exception.
In other words, calling the method directly without generating a token first will not change the password.
The recommendation is to follow the example order: first, generate a token for the email (using forgotPassword), then validate it with validateTokenPassword, and finally insert/register the new password using insertNewPassword.
Roles and Permissions
Create a New Role
If we want to create a new role, simply call the createRole function, passing a valid name as a parameter. For example:
Or:
Edit a Role
To edit a role, use the method: editRole(int $roleId, string $name)
:
where the first parameter is the role ID and the second is the new name we want to assign.
Or also:
But actually, it's better not to ;P
Delete a Role
To delete a role, as expected, call the deleteRole method, passing the ID of the role to be deleted:
Assigning Roles to Users
Now it may be useful to assign one or more roles to a user if we already have our list of roles created.
To do this, we call the assignRoleToUser method with two parameters: assignRoleToUser(int $userId, array $roles): bool
One parameter is the user ID, and the other is the ID(s) of the roles we want to assign.
Suppose we want to assign three roles to the user Jhon, whose ID is 27, and we want to assign the roles: 'editor', 'user', and 'moderator', corresponding to IDs 4, 5, and 7 respectively.
To do this, we should do the following:
It's worth noting here that if you assign a role that the user already has, nothing will happen; the rest of the roles will be assigned as usual.
Now that we've assigned roles to a user, we can also do the opposite remove roles from a user. For this, we have the method removeRoleFromUser: removeRoleFromUser(int $userId, array $roles): bool
This method accepts the same parameters as the previous one: the first is the user ID, and the second is an array containing the role IDs. It must receive at least one role to remove.
For example:
Permissions
Permissions are related to roles and vice versa. A user will have certain permissions depending on the role they have, so it is advisable to create a list of permissions. The number of roles and permissions we want to create will depend on the type of application and authorization we want to implement.
Create Permission
To start, if we want to create a new permission, we need to use the method createPermission: createPermission(string $name, string $description): bool
This method takes two parameters (name and description). The description is optional but useful.
Edit Permission
If we want to edit the name of an already created permission, we need to call the method editPermission: editPermission(int $permissionId, string $newName): bool
This method takes two parameters: an integer and a string. The integer represents the ID of the permission, and the string represents the new name we want to assign to it.
For example:
Remember, you can "ignore" the specific exceptions and catch the general one.
But once again and personally, I do not recommend it ;-)
Delete a permission
To delete a permission, simply run the following method: deletePermission(int $permissionId): bool
Assigning Permissions to Roles
As I mentioned earlier, a permission by itself does nothing; it is not useful unless it has an associated role. Therefore, it needs to be linked to a role. To do this, you should call the method assignPermissionToRole with two parameters: the role's ID and the permission's ID: assignPermissionToRole(int $roleId, int $permissionId)
Remove Permission from a Role
If we want to remove a permission from a role, we need to execute the method removePermissionFromRole: removePermissionFromRole(int $roleId, int $permissionId)
Where, once again, the first parameter is the role ID and the second parameter is the permission ID.
For example:
Roles and Permissions V.2
Earlier, we saw how to create roles and permissions and how to assign them to users. Now, there are several methods that allow us to view all available roles and permissions, as well as list all the roles a user has.
It’s important to mention that listing all the permissions of a user is not possible because permissions are tied to roles, not to the user. In other words, a user will have a permission or not depending on the role they have.
With this clarified, let's look at the methods mentioned earlier.
To find out all available roles, we call the method showRoles() and loop through it with a foreach:
There are also two additional methods: showRolesById() and showRolesByName(), which allow you to list only the IDs or names of the roles "more quickly." However, the main method (showRoles()) should generally suffice.
The same applies to permissions. We have the showPermissions() method to list all available permissions:
And just like before, we have the methods showPermissionsById() and showPermissionsByName() to display permissions by their ID or name, respectively.
All these methods are actually useful for scenarios like an admin panel, where it's necessary to see a list of all created roles and permissions.
There’s another interesting method if you want to know what roles a specific user has. For that, we have the following method:
userRoles($userId)
This method accepts a single parameter, which is the ID of the user you want to check.
For example, if you want to check what roles the user with ID "2" has, you would do the following:
And, as with the previous examples, there are also two methods available to display roles by their ID or name:
userRolesById($userId)
y userRolesByName($userId)
We may never use them, but for now, there they are!
Authorization
We have created users, roles, and permissions... Now, we are interested in implementing authorization in our application. For example, we might want to restrict access to the administration area only to administrators, or verify that a user has the necessary role before performing a specific action.
To achieve this, we have two methods to validate if a user has the required role or permission. The first one is:
hasRole(string $roleName, ?int $userId = null): bool
This method is used to check if the current user, meaning the one who is logged in, has a specific role. You just need to pass the role name like this:
As we have seen, the hasRole method can also accept a second optional parameter, which is the user’s identity. This is useful if we want to check if a specific user has a particular role.
For example:
In the previous example, instead of checking if the current user is "SuperAdmin", we checked if the user with identity 1 is.
For permissions, there is also a similar function, although, for now, it only checks the permission of the current user, that is, the one logged into the application.
For example, assuming we have a permission to create users, we can check if the current user has that permission.
To do this, we execute the hasPermission method, passing the name of the permission as a parameter.
Sessions
There's not much to say about sessions. There is simply a straightforward class for creating and retrieving session variables. Its usage is quite simple, with two main methods:
set(string $key, $value)
to create a session.
get(string $key)
to get the session.
We have some more methods which are:
has($key)
: To check if a key exists in the session.
remove($key)
: To remove a key-value pair from the session.
destroy()
: Completely destroys the session.
It is important to mention that when a user is logged in, two sessions are automatically created. One is for the user's identity, called "userId", and the other is for the duration of the active session, named "expire_time".
To retrieve these sessions, for example, the ID of the logged-in user, we need to use the get()
method of the Session class like this:
Session Duration
As mentioned earlier, when a user logs in, two sessions are created: one that contains the user ID, and another that holds the session's duration/expiry time.
Currently, the default session duration is set to one hour, but this can be changed using the constant SESSION_EXPIRATION found in the config.php file.
To determine the exact duration of the session, you can check the value of "expire_time", which can be done like this:
However, if you do the above, you'll get the date in timestamp format, which is somewhat difficult to read. So, there's a better method called expirationTime() that allows you to check this data in a more readable format.
It can also be useful, before accessing a certain part of our application, to check not only if the user is logged in (remember, the isLoggedIn() method is for that) but also if there is an active and valid session. To do this, you can use the isValid() method of the Session class like this:
dulceMail
This is a super simple class that essentially uses PHP's native mail()
function. It is mainly for sending and receiving emails in the simplest way possible. Please keep that in mind. If you need something more secure, consider exploring alternatives like "PHPMailer" and integrating it with dulceAuth.
To use this class its use is simple:
But as always, a more complete example including exceptions would be as follows:
Create a service
Through bootstrap, all the services that dulceAuth needs to work are created/started, however, sometimes, we may need other additional services (classes). Well, this is possible and easy to do.
We just need to run the dulceAuth service container like this:
Por ejemplo:
The above example would add a new class to dulceAuth which would not come by default. I think it's pretty easy to understand ;-)