Part A: Work with Client Sessions and data persistence using MongoDB to add user registration and Login/Logout functionality & tracking (logging)
Part B: Update the password storage logic to include “hashed” passwords (using bcrypt.js)
You can view a sample solution online here: https://as6-322-sample-sites.vercel.app/
For this assignment, we will be allowing users to “register” for an account on your National Historic Sites App. Once users are registered, they can log in and gain access to the add / edit & delete functionality created in assignment 5. By default, this functionality will be hidden from the end user and unauthenticated users will only see the “sites” / “site” and “about” views / top menu links. Once this is complete, we will add bcrypt.js to our code to ensure that all stored passwords are “hashed”
NOTE: If you are unable to start this assignment because Assignment 5 was incomplete – email your professor for a clean version of the Assignment 5 files to start from.
If you have not already done so, create a new account on https://www.mongodb.com/cloud/atlas to host our new MongoDB database:
For our app to be able to register new users and authenticate existing users, we must create a convenient way to access this stored information. To accomplish this, we will need to add a new module called “auth-service“. This module will be responsible for storing and retrieving user information (user & password) using our newly created MongoDB database:
Each of the below functions are designed to work with the User Object (defined by userSchema). Once again, since we have no way of knowing how long each function will take, every one of the below functions must return a promise that passes the data via its “resolve” method (or if an error was encountered, passes an error message via its “reject” method). When we access these methods from the server.js file, we will be assuming that they return a promise and will respond appropriately with .then() and .catch() (or with async / await and try / catch).
return new Promise(function (resolve, reject) {
let db = mongoose.createConnection(process.env.MONGODB);
db.on(‘error’, (err)=>{
reject(err); // reject the promise with the provided error
});
db.once(‘open’, ()=>{
User = db.model(“users”, userSchema);
resolve();
});
});
users[0].loginHistory.pop()
}
Once the code for auth-service.js is complete, we need to add its initialize method to the promise chain surrounding our app.listen() function call within our server.js file, for example:
Your code should currently look something like this:
siteData.initialize()
.then(function(){
app.listen(HTTP_PORT, function(){
console.log(`app listening on: ${HTTP_PORT}`);
});
}).catch(function(err){
console.log(`unable to start server: ${err}`);
});
Since our server also requires authData to be working properly, we must add its initialize method (ie: authData.initialize) to the promise chain:
siteData.initialize()
.then(authData.initialize)
.then(function(){
app.listen(HTTP_PORT, function(){
console.log(`app listening on: ${HTTP_PORT}`);
});
}).catch(function(err){
console.log(`unable to start server: ${err}`);
});
Now that we have a back-end to store user credentials and data, we must download and “require” the “client-sessions” module using NPM and correctly configure our app to use the middleware:
app.use((req, res, next) => {
res.locals.session = req.session;
next();
});
With our app now capable of respecting client sessions and communicating with MongoDB to register/validate users, we need to create routes that enable the user to register for an account and login / logout of the system (above our 404 middleware function). Once this is complete, we will create the corresponding views (Step 6).
req.session.user = {
userName: // authenticated user’s userName
email: // authenticated user’s email
loginHistory: // authenticated user’s loginHistory
}
res.redirect(‘/sites);
})
Lastly, to complete the register / login functionality, we must update/create the following .ejs files (views) within the views directory.
<li>
<details>
<summary>Account: <%= session.user.userName %></summary>
<ul class=”p-2 right-0″>
<li><a class=”<%= (page == “/addSite”) ? ‘active’ : ” %>” href=”/addSite”>Add Site</a></li>
<li><a class=”<%= (page == “/userHistory”) ? ‘active’ : ” %>” href=”/userHistory”>User History</a></li>
<li><a href=”/logout”>Log Out</a></li>
</ul>
</details>
</li>
<li>
<details>
<summary>Account</summary>
<ul class=”p-2 right-0″>
<li><a class=”<%= (page == “/login”) ? ‘active’ : ” %>” href=”/login”>Login</a></li>
<li><a class=”<%= (page == “/register”) ? ‘active’ : ” %>” href=”/register”>Register</a></li>
</ul>
</details>
</li>
<svg xmlns=”http://www.w3.org/2000/svg” class=”stroke-current shrink-0 h-6 w-6″ fill=”none” viewBox=”0 0 24 24″><path stroke-linecap=”round” stroke-linejoin=”round” stroke-width=”2″ d=”M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z” /></svg>
<span><%= errorMessage %></span>
</div>
only if there is an errorMessage rendered with the view.
<svg xmlns=”http://www.w3.org/2000/svg” class=”stroke-current shrink-0 h-6 w-6″ fill=”none” viewBox=”0 0 24 24″><path stroke-linecap=”round” stroke-linejoin=”round” stroke-width=”2″ d=”M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z” /></svg>
<span><%= errorMessage %></span>
</div>
only if there is an errorMessage rendered with the view.
<div class=”alert”>
<svg xmlns=”http://www.w3.org/2000/svg” class=”stroke-current shrink-0 h-6 w-6″ fill=”none” viewBox=”0 0 24 24″><path stroke-linecap=”round” stroke-linejoin=”round” stroke-width=”2″ d=”M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z” /></svg>
<span><%= successMessage %></span>
</div><br />
<a href=”/login” class=”btn btn-success”>
Proceed to Log in
</a>
only if there is a successMessage rendered with the view (this will be rendered instead of the form).
We will be using the “bcryptjs” 3rd party module, so we must go through the usual procedure to obtain it (and include it in our “auth-service.js” module).
Since all our new users will have encrypted (hashed) password, we will need to remove all our existing test users. This can be done easily by logging into your MongoDB Atlas account and clicking on the “collections” for your existing cluster.
Now that we have the bcryptjs module included and our Users collection has been cleaned out, we can focus on updating the other two functions in our auth-service.js module. We will be using bcrypt to encrypt (hash) passwords in registerUser(userData) and validate user passwords against the encrypted passwords in checkUser(userData):
bcrypt.hash(“myPassword123”, 10).then(hash=>{ // Hash the password using a Salt that was generated using 10 rounds
// TODO: Store the resulting “hash” value in the DB
})
.catch(err=>{
console.log(err); // Show any errors that occurred during the process
});
bcrypt.compare(“myPassword123”, hash).then((result) => {
// result === true if it matches and result === false if it does not match
});
If the passwords do not match (ie: result === false) reject the returned promise with the message “Incorrect Password for user: userName” where userName is the userData.userName value
To see a completed version of this app running, visit: https://as6-322-sample-sites.vercel.app/
/********************************************************************************
* WEB322 – Assignment 06
*
* I declare that this assignment is my own work in accordance with Seneca’s
* Academic Integrity Policy:
*
* https://www.senecacollege.ca/about/policies/academic-integrity-policy.html
*
* Name: ______________________ Student ID: ______________ Date: ______________
*
* Published URL:
*
********************************************************************************/
Reviews
There are no reviews yet.