If you're developing any kind of project chances are one day you'll do the thing that made a lot of developers have a mental breakdown - authentication.
This is the part where everyone is arguing what is the best way to do it, which best practices are truly the best. Also, there is a ton of jargon you'll have to make sense of during your "figuring out" phase. Obviously, there's no one holly right way to do authentication (as you can tell by zillion of techniques out there), and a lot of nuances are coming from the unique processes that each developer is trying to build.
In this post, I'll show you the technique that I use for most of my projects, where I'm doing user management.
Let's say that you have 2 types of users in your project: customer and vendor. They have access to different functionalities but also have some functions to share. The goal is to create entities for our database and authentication that will help us to:
- create entities that will be easy to user and store in the database,
- simplify the role-based authentication process,
- implement it in a simple way for the developer.
The fields that I have in UserEntity are:
email - generally it's up to you to decide where to put the email. You can have it on Customer/Vendor entity too, I'm just leaving it here because during the login process I'm using UserEntity, so I don't need to make a separate call to the database to find the email of the user on CustomerEntity.
emailConfirmed - the name speaks for itself here. During the registration process when I'm first creating the UserEntity, I'm setting the value to this field false (you can also do it with your ORM, by setting default value false) and I'm changing it when the customer/vendor went through the link in their email confirmation email.
emailConfirmToken - this field is containing the unique token by which I will confirm the email address of the user in my system. I'm just generating a new GUID and creating a Get request in the controller on a route like /users/confirm/:emailConfirmed, and then checking if any user has the token in the database.
passwordHash - this field is containing the password of your customer/vendor combined with salt and hashed using some algorithm like MD5 or Sha256.
salt - this field is containing the salt for your password. A random string that is generated uniquely for each password.
concurrencyStamp - this field is containing the concurrency stamp for your user. I use this field to check that no other user has modified that a database when saving changes to that record.
lockoutEnabled - this field is containing true or false values and indicates if the user locked their account by accessing to many times with wrong credentials.
accountaAccessFailCount - this field is containing the number of times when the user tried to access their account with wrong credentials.
Usually, I'm locking the account after 3 false accesses.lockoutTime - this field is containing the date and time when the account has been locked out.
resetPasswordStamp - this field is containing the token by which I will authenticate the user when they try to reset their password. I'm sending an email with a link where they need to enter their new password. The route for that link will be something like this /user/resetpassword/:resetPasswordStamp.
resetPasswordDate - this field is containing the date and time when the resetPasswordStamp was generated so I can calculate it's validity period. Usually, it's 1 day.
role - this field is containing the role of the user. Role is an enum that contains all available roles for the project (in this case, you guessed it customer or vendor), so during authentication, I can recognize where I can redirect the user, and to which functionality they have access.
Here are the completed entities:
export class CustomerEntity {
id: Guid;
fullname: string;
profilePicture: string;
bio: string;
user: UsersEntity;
userId: string;
}
export class VendorEntity {
id: Guid;
fullName: string;
bio: string;
location: string;
user: UsersEntity;
userId: string;
}
export class UsersEntity {
id: Guid;
email: string;
emailConfirmed: boolean;
emailConfirmToken: Guid;
passwordHash: string;
salt: string;
concurrencyStamp: Guid;
lockoutEnabled: boolean;
accountaAccessFailCount: number;
lockoutTime: Date;
resetPasswordStamp: Guid;
resetPasswordDate: Date;
role: Role;
}
Customer entity and Vendor entity have fields userId and user, so each one can have an associated user.
Hope this helps the newbies to figure out how to organize the user entities.
I would love to hear about your experience with this!
Top comments (0)