This project is Live at: http://saadzafar.com
I have developed this project using ASP.NET with MVC, C# as server side language and SQL server as database. This project does not interact directly with database at any level. All of its database level operations are being done by REST API specially developed for this project. Below-mentioned is overview of application Request and Response flow:
This project has below-mentioned pages:- Signup - Used To Create New User and Confirm User Email
- Login - Used To Login Using Already Created Account
- Password Reset Request - Used To Send Password Reset Instruction To User Email
- Password Reset - Used To Update New Password Entered By User
- Home - Home Page Displayed After User Successfully Logged In
This below image will show a New User SignUp Request. I have this to help you understand (easily) how the application works.
In my effort to make our application secure I have implemented two level validations:
- Front End Jquery Validations
- Back End C# Validations
- Code Reusability
- Extensibility
- Modular Approach
No controller is calling REST API directly all calls are going through "JumpCut.Services" project. Currently there is only one service named as "ServiceLayer". In future when we will add more modules in it. All modules will have independent services in "JumpCut.Services" project. We will also use this layer to perform basic data manipulation on data received from API. So if there is some change required in future which affects only data manipulation we can simply work this project and do a partial deployment on server. By doing this we can save time and risk of full deployment.
I am also re-using code for validations at front end and back end levels. For front end I have used HTML attribute "name" to identify elements instead of using IDs (which should be unique application wide). By using name I have re-used methods to display error messages for each control. On back end, Validations method for each control type is written (FullName, Email and Password). Then these methods are being used for validations of all pages.
Above mentioned are just some examples I have implemented this on application wide. In my last job there were rapid changes required during an application development and even after deployment some quick changes and enhancements were often requested. So I developed this habbit to code like this to make code more manageable.
Security is one of the major part of website development these days. I have implemented some of the basic security features here but obviously we can extend these in our production project.
- Two Level User Input Validations
- Encrypting User Data of Data
- Using OAuth Authentication
- Storing Encrypted Data To Database
- Protection Against SQL Injection
- Using SQL User With Limited Access to Database Operations
These are some of the steps which I have implemented. Although I also wanted to implment safety from brute force attacks. Which can be implemented in production environment. Apart from this there are many other securities which is necessary for securing web applications.
I am using MS SQL Server database for this project. Tables are mentioned below:
- Users
- UsersModified
- Roles
- ExceptionLog
- APIAccessToken
-
Moduler Approach - If we need to change anything in our query. We only need to change that query and execute ALTER statement of stored procedure in database and we are done. It is so easy to manage database with stored procedure rather than any other approach.
-
Safety - Stored procedure provide us safety from SQL injection and it also provide a layer of encapsulation for our database logics.
-
Fast Execution - As it is commonly known as that SQL Server stored a parsed and complied version of stored procedure. So on re-occuring use of same query this will same us enourmous time and system resources.
At the end, I personally prefer flat table structures where I can get all of our most used columns in one table rather having to create multiple views, or write joins to fetch data from different tables. Flat table structure save time and increase database processing speed. It also creates problem when our table grows too much. We can deal that problem with data archiving. Tables which we were going to need here are not such tables which grows that much.
Serial No | Column Name | DataType | Default Value | Nullable | Purpose |
---|---|---|---|---|---|
1 | UserId | Int | Auto Increment of 7 | No | Primary Key of Table |
2 | FullName | Varchar(60) | No | No | Name of User |
3 | UserPassword | Varchar(Max) | No | No | Encrypted Password of User |
4 | EmailId | Varchar(100) | No | No | Email of user |
5 | RoleId | Int | No | No | Foreign Key From Roles Table |
6 | EmailVerificationKey | UniqueIdentifier | No | No | Email Confirmation Token |
7 | EmailVerified | BIT | False | No | Email Verification Status |
8 | EmailVerificationDate | DateTime | No | Yes | Timestamp When Email Verified |
9 | LastLoginAttempt | DateTime | No | Yes | Timestamp of Last Login Attempt |
10 | LastLoginSuccess | Bit | No | Yes | Outcome of Last Login Attempt |
11 | IsActive | Bit | False | No | User Status. Alternate of Deleting User |
12 | PasswordResetRequest | Bit | False | No | Password Reset Requested Or Not |
13 | PasswordResetKey | UniqueIdentifier | No | Yes | Password Reset Token |
14 | DateCreated | DateTime | GetDate() | No | |
15 | DateModified | DateTime | No | Yes | Timestamp When User Record is Modified |
16 | ModifiedBy | Int | No | Yes | UserId if Who Modified User Record. For Future Use. |
We can keep this table in a separate database so that our production database and its transanction log will not become heavier day by day.
Serial No | Column Name | DataType | Default Value | Nullable | Purpose |
---|---|---|---|---|---|
1 | RoleId | Int | Auto Increment of 1 | No | Primary Key of Table |
2 | RoleName | Varchar(20) | No | No | Name of Role |
3 | IsActive | Bit | True | No | Status of Role |
4 | DateCreated | DateTime | GetDate() | No | Timestamp When New User is Created |
5 | CreatedBy | Int | No | No | UserId who Created This Role |
6 | DateModified | DateTime | No | Yes | Timestamp When Role Record is Modified |
7 | ModifiedBy | Int | No | Yes | UserId if Who Modified User Record. For Future Use |
This table will help us define different roles. Currently we only had two roles. User and APIUser
Serial No | Column Name | DataType | Default Value | Nullable | Purpose |
---|---|---|---|---|---|
1 | ExceptionId | Int | Auto Increment of 1 | No | Primary Key of Table |
2 | ExceptionMessage | Varchar(Max) | No | No | Summary Message of Exception |
3 | ExceptionStackTrace | Varchar(Max) | No | No | Contains call trace of exception causing method |
4 | InnerExceptionMessage | Varchar(Max) | No | No | Summary Message of Inner Exception |
5 | InnerExceptionStackTrace | Varchar(Max) | No | No | Contains call trace of inner exception causing method |
6 | APIEndpoint | Varchar(100) | No | No | Web API Exception Causing EndPoint URL |
7 | DateCreated | DateTime | GetDate() | No | Timestamp of When Exception is Created |
This table keeps record of all exception caused by applicaiton and ExceptionId is sent to user if he/she want to contact support. If customer shares exception id (named as Error Code on front end) then it will be easier to trace and fix the problem. Ever if user does not share we are still capturing in our database. I am also using some fixed error codes to identify some logical errors.
For database connectivity I have created an independent REST API and all database operations are being performed by this API. Our web application is not interacting with database directly. This helps in maintaining security of our web server. To use web api user have to generate access token. We are storing that access token in this table.
Serial No | Column Name | DataType | Default Value | Nullable | Purpose |
---|---|---|---|---|---|
1 | AccessTokenId | Int | Auto Increment of 1 | No | Primary Key of Table |
2 | UserId | Int | No | No | Foreign Key from Users Table |
3 | AccessToken | Varchar(Max) | No | No | Access Token Generated by Web API |
4 | IsActive | Bit | False | No | Status of Access Token |
5 | DateGenerated | DateTime | GetDate() | No | Timestamp of When AccessToken is Created |
6 | ValidForDays | Int | No | No | No of Days Access Token is Valid After Generation |
7 | ModifiedOn | DateTime | No | No | Timestamp of When Record is Modified |
Note: For frontend of this application I have used a free template from ColorLib. Although I did some modification. But reference to theme is here: https://colorlib.com/etc/lf/Login_v5/index.html