tirsdag 23. februar 2016

Node.js, Express and Mongodb beginner tutorial; make a simple comment site. | Part 2: Sign Up and Log In with jade


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.

Ingen kommentarer:

Legg inn en kommentar