This is a continuation of a tutorial. If you have not finished step 1, do that first: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner.html
Step 3 – Sign up page
I chose to
make the signup page first, because you need content before you can show it, and the
point is that you have to be logged in to comment.
As I
mentioned before I use the jade engine, which can generate HTML pages. I think jade is
both simpler and faster to write than normal HTML. For the signup page, open
the views folder and make an empty file called signup.jade.
This is my signup.jade file:
doctype html html head title Sign Up link(rel="stylesheet", href="/stylesheets/style.css") body h1 Sign Up form(method="post") input(name="username", placeholder="Username", type="text") br input(name="password", placeholder="Password", type="password") br input(value="Sign Up", type="submit") br br a(href="/login") Log in
The format
is (in my opinon) not very hard to understand. Instead of having xml tags
inside each other, like you do in HTML, you nest tags inside each other by
using indents (the tab button).
You start
every line with the tag you want to use. Afterwards, you could have a
parenthesis. Inside the parenthesis, you can set attributes like those that I
have done over. If you want content inside the tags, you just do like what I
have done inside the title tag. Just a space and then the content inside the
tag.
As you may
remember, you have static files inside the public folder, like the
stylesheets/style.css. I use this file as my CSS file. You can set up the CSS to
get the design you want. (you will probably
change it as it is not very nice):
html{ font-family:Arial; text-align:center; background-color:gray; } div { margin:auto; } table { border-collapse: collapse; margin:auto; width:40%; } table, th, td { border: 1px solid black; text-align:center; } textarea{ width:40%; margin:auto; }
Now that
the signup page is ready, we have to say to the node.js that this is the page
that we open when someone go to “/signup”. Therefore add the following to the
app.js file before the error message functions:
app.get("/signup",function(req, res) { res.render("signup"); });
This
function says that when someone is going to the “yourapp.com/signup”, the web
app shall send the signup.jade file as an HTML file to the user.
app.get
means that when someone is sending a GET-request to the site, this is what is
going to happen.
Parameter
req, is short for request and includes information about the user’s request,
like his/her cookies and IP-address.
Parameter
res, is short for respond and is what the web app send back to the user.
What is
much harder is to register the user in the database. Here is what I did:
//First of all I made a function that hashes passwords:
function to_hash(pass){
//takes the argument pass that is what is going to be hashed
return crypto.createHash("sha256").update(pass).digest("base64");
//this uses the crypto add-on to make hashes out of the password. createHash takes the hashing method as argument. The update method tells what is going to be hashed, and the digest menthod tells what format the output should be in.
} app.post("/signup",function(req,res){
//app.post because this is a post request.
if (req.body.username=="" || req.body.password==""){
//req.body.variable gets the variables that is sent through the HTML.
req.send("Sorry, invalid username and/or password");
//Because you cannot have a empty username or password.
}
else
{
MongoClient.connect("mongodb://localhost:27017/admin",function (err, db) {
//This connects to the mongodb. “mongo://localhost:27017/” is the standard URL for mongodb and “/admin” is the database inside mongodb we want to connect to.
if (err) { console.log('Unable to connect to the mongoDB server. Error:'+ err);
//If something goes wrong, we see that inside the logs.
}
else
{
console.log('Connection established to mongodb://localhost:27017/admin');
var users=db.collection("users");
//this connects to a collection inside node.js. This is the about the same as a table in SQL-databases.
users.findOne({"username":req.body.username},function(e,doc){
//check if there are someone who has already registered the username in the users collections. Doc is the result that is sent back from the query.
if (doc==null){
//if no one has the username, you are free to register.
users.insert({"username":req.body.username,"password":to_hash("Random salt"+ req.body.password+"Other random salt")},function (err, result) {
//users.insert insert a new instance into a collection. Change the salts into other strings, because the salts are secret, otherwise hackers can crack the passwords.
if (err){
console.log(err);
//log the error if any.
res.send("Sorry, server error.");
//tell the user if there is an error with the request.
}
else
{
res.send("Success");
//tell that the user successfully registered the user account.
db.close();
//close connection with the database as you no longer need it.
}
});
}
else
{
res.send("Sorry, username already taken.");
//if the username was already taken, tell the user.
db.close(); } }); } }); } });
Now you
need two terminals to check if everything is working.
One where
you start mongodb (it has to be running if mongodb requests shall work):
C:\ > mongod
And another
that is set inside your node.js app directory:
C:\nodeapp\testapp> npm start
Go to http://localhost:3000/signup and try if
it is working-
Hopefully,
you can register and get the result “success”.
To be sure that everything works you shold be able to see
a logs in the terminal window where you started mongodb. If everything went
fine you would get a result like this:
2016-02-23T14:54:29.698+0000 [initandlisten] connection accepted from 127.0.0.1:59804 #1 (1 connection now open) 2016-02-23T14:54:29.722+0000 [initandlisten] connection accepted from 127.0.0.1:59806 #2 (2 connections now open) 2016-02-23T14:54:29.728+0000 [conn1] end connection 127.0.0.1:59804 (1 connection now open) 2016-02-23T14:54:29.744+0000 [conn2] allocating new ns file /data/db/admin.ns, filling with zeroes... 2016-02-23T14:54:29.825+0000 [FileAllocator] allocating new datafile /data/db/admin.0, filling with zeroes... 2016-02-23T14:54:29.825+0000 [FileAllocator] creating directory /data/db/_tmp 2016-02-23T14:54:29.834+0000 [FileAllocator] done allocating datafile /data/db/admin.0, size: 64MB, took 0.002 secs 2016-02-23T14:54:29.836+0000 [conn2] build index on: admin.users properties: { v: 1, key: { _id: 1 }, name: "_id_", ns: "admin.users" } 2016-02-23T14:54:29.836+0000 [conn2] added index to empty collection 2016-02-23T14:54:29.843+0000 [conn2] end connection 127.0.0.1:59806 (0 connections now open)
This says
that mongodb made a new collection for your request and that the user is added.
Step 4 – Login Page
For a login
page, you need a new jade file where you can log in, like this one (call it “login.jade”,
still in the views folder):
doctype html html head title Log In link(rel="stylesheet", href="/stylesheets/style.css") body h1 Log In form(method="post") input(name="username", placeholder="Username", type="text") br input(name="password", placeholder="Password", type="password") br input(value="Log In", type="submit") br br a(href="/signup") Sign Up
You have to
tell node.js that it is this page it is going to show, when people enter the “/login”
URL:
app.get("/login",function(req,res){ res.render("login"); });
And as
before, this is the easy part. To check if the login is valid, you can use the
following code. Fortunately, the concepts are basically the same:
function random_string(){
//we check whether a user is logged in, by checking his/her cookies. To prevent anyone from using another person’s hash in the cookies, we have to give people random hashes.
return crypto.randomBytes(139).toString('base64');
//the randomBytes function makes random bytes than can be transformed to a string. The randomBytes function takes a parameter that tells how many bytes that is going to be made. 139 is more than enough.
} app.post("/login",function(req,res){
MongoClient.connect("mongodb://localhost:27017/admin",function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:' + err);
}
else
{
console.log('Connection established to mongodb://localhost:27017/admin');
var users=db.collection("users");
users.findOne({"username":req.body.username},function(e,docs){
//check if there are users with the username that is given
if(e) throw e;
//An other way to log errors.
if (docs==null){
//if there are no users with username, tell the user so.
res.send("No user with that username.");
db.close();
}
else if (docs.password== to_hash("Random salt"+ req.body.password+"Other random salt")){
//if the password the user gave, is the same as the one he/she gave upon signup, the two hash values are the same.
var session_id=random_string();
res.cookie("session_id",session_id);
//this gives the user a random string in the cookies, that proves that he/she is logged in.
users.update({"username":docs.username},{$set:{"session_id":to_hash("Another random salt"+session_id+"Randomed hash")}},function(err,result){
//we crypt the session_id so that hackers cannot pretend to be users if they get control over the database.
if (err) throw err;
db.close();
res.write("success");
//tell user if login is successful.
res.end();
});
}
else{
res.send("Wrong username or password");
//tell user if password or username is wrong.
db.close();
}
});
}
});
});
Test if
this work the same way as you checked whether the signup page worked.
The login
page is at http://localhost:3000/login
If it works:
Congrats!
You have a working user validation system.
You can now go on to part 3 of the tutorial: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner_24.html
If there are any questions or suggestions of things I could have done better, please use comment section below.
You can now go on to part 3 of the tutorial: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner_24.html
If there are any questions or suggestions of things I could have done better, please use comment section below.
Ingen kommentarer:
Legg inn en kommentar