Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Unique Authentication using Magic of HTML5 and WCF

4.91/5 (28 votes)
8 Mar 2012CPOL7 min read 72.1K   3.6K  
Unique Authentication using magic of HTML5 and WCF

login.JPG

afterlogin.JPG

Table of Contents

Introduction

This is my first hands on in HTML5. One day I thought about making an application which is simple and fancy looking as well. I had not worked earlier in HTML5, but once I saw the new features and tags in HTML5, I decided to make something new in core HTML. The biggest advantage in using HTML5 is that it is light weighted, platform independent and best for mobile applications like Iphone, Android (For Win 7 mobile, it’s not supported because Microsoft is still experimenting with HTML5 and has not yet introduced HTML5 in mobile). Enough about my thoughts, let's moves on to the application. This application is based on Login form, but it is not a simple authentication form.

In this article, we'll build a innovative login form, where the user drops a “webid” file in the login form to authenticate. The file contains an image and some information about the card holder. It uses a great feature of HTML5, WCF and feature called WebId.

System Requirements

The most essential requirement to run this application is HTML5 supported browser.

Browser: Firefox 3.6.3, Google Chrome 5.0, Apple Safari 4.05, Opera 10.53

What You Can Learn

As a beginner, you can learn the following features:

  1. HTML5, CSS3, WebKit
  2. Ajax call to WCF service using JavaScript
  3. JSON Operation in JavaScript.

Fancy Signup Form

sigup.JPG

I used this term (fancy) because I will tell you in simple terms how you can make a form look attractive.

As in figure of signup form, I divide the form in 3 sections:

  1. User detail
  2. Address detail
  3. Image Upload

All sections are pretty simple except image upload section where I did not give any upload button. So how I can upload image? So I used the feature of drag and drop of HTML5 where you have to just drag and drop image in box. But here I applied a constraint along with it. You can’t drag and drop image of more than 10 KB size. Since this is simple demo application, I was not going deep into it to resize image of any size, so I just put the constraint.

As you can see in the signup form rounded corner box, this is very simple CSS for webkit in HTML5:

-moz-border-radius: 5px;
-webkit-border-radius: 5px;
-khtml-border-radius: 5px;
border-radius: 5px;

You can give gradient effect using webkit at background in one line.

HTML
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#526ACE), to(#526ACE));

And you can browse more details in CSS from my code in the attachment.

Image Upload

Especially I wanted to give more details about this feature because it is more interesting for lazy people who don’t want to navigate an image from desktop location and then upload it. I saved 5-6 seconds by using drag and drop feature of HTML5.

Let's have a look at how I can accomplish this task.

HTML
<fieldset>
        <legend>Image Load</legend>
        <ol>
            <li><legend>Drag and Drop your Image here<legend>
                <div id="holder">
                </div>
                <div id="status">
                </div>

                <script>
                    var y = null;
                    var holder = document.getElementById('holder'),
                    state = document.getElementById('status');

                    if (typeof window.FileReader === 'undefined') {
                        state.className = 'fail';
                    } else {
                    }
                    holder.ondragover = function()
			{ this.className = 'hover'; return false; };
                    holder.ondragend = function()
			{ this.className = ''; return false; };
                    holder.ondrop = function(e) {
                        this.className = '';
                        e.preventDefault();
                        var size = e.dataTransfer.files[0].size;
                        if (size > 10000) {
                            alert("Your image size is greater than
				10 kb please Shrink image size");
                            window.location.reload(true);
                        }
                        else {
                            var file = e.dataTransfer.files[0],
                            reader = new FileReader();

                            reader.onload = function(event) {
                                holder.style.background =
				'url(' + event.target.result + ') no-repeat center';
                                y = 'url(' + event.target.result + ') no-repeat center';
                            };
                            reader.readAsDataURL(file);
                            //var x = document.getElementById(el);
                            state.className = 'success';
                            state.innerHTML = 'Image SuccessFully Uploaded';
                            return false;
                        }
                    };
                </script></li>
        </ol>
    </fieldset>

Although this code is self explanatory, I want to give some details on drag and drop feature. As you can see, I used div as a place in the form for drag and drop.

In the JavaScript, we are:

  1. Searching for the drop target in the DOM using document.getElementByID.
  2. When drag over event is fired (when the user drags the element over another), it will trigger the CSS class.
  3. Bind the drop event, and within there, grab some data about what was dropped.
  4. Now read the stream by reader and it will generate event.target.result that will help us to get an image in base 64 format which we further used as in webid.

For more details on new tags, please move to resources.

That is enough for fancy form decoration and JavaScript. Now we will move to Ajax calling WCF service.

infosignup.JPG

Ajax Calls to WCF Service

Before describing snippet of Ajax call, I would like to give you a few details on WCF service at the server end. The service exposed as a REST URI in Post method. I want to send data as post because data would be too large. I used response format in JSON because it is easy to use in Ajax call. As this is a demo application, I did not use WCF in a professional way and just use as rooky.

Simple one method Signup User:

C#
[OperationContract]
        [WebInvoke(Method = "*",
            ResponseFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped,
            UriTemplate = "SignUpUser")]
        string SignUpUser(string name, string email,string language, string phoneno,
        string gender, string country, string image);

Implementation of the SignUpUser is very straight forward. I just make a webid format just as a JSON Format and send it to the appropriate mail. For making JSON string, I used inbuilt .NET serializer.

C#
JavaScriptSerializer oSerializer = new JavaScriptSerializer();
            string sJSON = oSerializer.Serialize(jsonWebIdList);

Web ID Format

We should create a file that we can drop on the form. It will be a text file with the extension “webid”. The content is a JSON object containing all the data we need. One part of the file, named userdata, lists things as name, age, etc. Remember that you shouldn’t trust the data in the file. It should only be used as feedback to the user on the login screen.

JavaScript
{
	"filetype": "webid",
	"signed":1234567890,

	"userdata": {
		"id": 1,
		"name":"XYZ",
		"gender": "Male",
		"birthdate":19610804,
		"phone":"1234567890",
		"country":"us",
		"language":"en_US",
		"image": "" // Base 64 Image format
	},
	"keys": {
		"Null"
	}
}

Now I call signup service from JavaScript that will look like this:

JavaScript
var baseUrl = "http://localhost:54976/RestServiceImpl.svc/";

//Ajax request function for making ajax calling through other object
function AjaxRequest(baseurl, type, callbackResponse, parameterString) {
    this.BaseURL = baseurl;
    this.Type = type;
    this.Callback = callbackResponse;
    this.createXmlRequestObject();
    this.ParemeterString = parameterString;
}

// Create XMLHTTP OBJECT
AjaxRequest.prototype.createXmlRequestObject = function() {
    if (window.ActiveXObject) { // INTERNET EXPLORER
        try {
            this.xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) {
            this.xmlHttp = false;
        }
    }
    else { // OTHER BROWSERS
        try {
            this.xmlHttp = new XMLHttpRequest()
        } catch (f) {
            this.xmlHttp = false;
        }
    }

    if (!this.xmlHttp) { // RETURN THE OBJECT OR DISPLAY ERROR
        alert('there was an error creating the xmlhttp object');
    } else {
        //return this.xmlhttp;
    }
}

AjaxRequest.prototype.MakeRequest = function() {
    try {

        // PROCEED ONLY IF OBJECT IS NOT BUSY
        if (this.xmlHttp.readyState === 4 || this.xmlHttp.readyState === 0) {

            // EXECUTE THE PAGE ON THE SERVER AND PASS QUERYSTRING
            this.xmlHttp.open(this.Type, this.BaseURL, false);

            var that = this;
            // DEFINE METHOD TO HANDLE THE RESPONSE
            this.xmlHttp.onreadystatechange = function() {
                try {

                    // MOVE FORWARD IF TRANSACTION COMPLETE
                    alert(that.xmlHttp.readyState);
                    if (that.xmlHttp.readyState == 4) {
                        alert(that.xmlHttp.status);
                        // STATUS OF 200 INDICATES COMPLETED CORRECTLY
                        if (that.xmlHttp.status == 200) {

                            // WILL HOLD THE XML DOCUMENT
                            var xmldoc;
                            if (window.ActiveXObject) { // INTERNET EXPLORER
                                xmldoc = new ActiveXObject("Microsoft.XMLDOM");
                                xmldoc.async = "false";
                                that.Callback(that.xmlHttp.responseText);
                            }
                            else { // OTHER BROWSERS
                                //writeMessage("MakeRequest", that.xmlHttp.responseText);
                                that.Callback(that.xmlHttp.responseText);
                            }
                        }
                    }
                }
                catch (e)
                { alert(e) }
            }

            switch (this.Type) {
                case "GET":
                    //this.xmlHttp.setRequestHeader("Content-type", "application/json");
                    // MAKE CALL
                    this.xmlHttp.send(this.BaseURL);
                    break;
                case "POST":
                    this.xmlHttp.setRequestHeader("Content-type", "application/json");
                    this.xmlHttp.send(this.ParemeterString)
            }

        }
        else {
            // IF CONNECTION IS BUSY, WAIT AND RETRY
            setTimeout('GetAllAppsService', 5000);
        }
    } catch (e) {
        alert(e);
    }
}

As you can see from the above code function, AjaxRequest creates XMLHttpRequest() object which further calls method AjaxRequest.prototype.MakeRequest. I used JavaScript in object oriented so that it can be used anywhere in calls easily. What you need to do is just make an object of AjaxRequest and call the function MakeRequest. For more details on how to use JavaScript as OOPS, please follow the trick from here.

You can also get some help form this article here.

Now call the Ajax request to WCF service just like:

JavaScript
AuthenticateLogin.prototype.SendDetailsToServer = function(parameters, localId) {

    var url = baseUrl + "SignUpUser";
    var parameterString = "{";

    for (var i = 0; i < parameters.length; i++) {
        parameterString = parameterString + '"'
                  + parameters[i][0] + '":"'
                  + parameters[i][1] + '" ,';
    }

    parameterString = parameterString.slice(0, parameterString.length - 1);
    //writeMessage("AddNewReminderToServer", "Local id : "+localId);
    parameterString = parameterString + "}";
    var ajaxRequestObject = new AjaxRequest(url, "POST", function(responseText) {
        var jsonobj = eval('(' + responseText + ')');
        var result = jsonobj.SignUpUserResult;
        if (result == "Successful") {
            alert("SuccessfullyMail sent and you will redirect to login Page");
            window.location = "http://localhost:54976/UI/latestLogin.htm";
        }
        else {
            alert("Message sending Fail! Please try again");
            window.location.reload(true);
        }
        //        writeMessage("handleresponse", jsonstr);
        //        writeMessage(" -> local id :", ajaxRequestObject.TempItemID);
    }, parameterString);

    ajaxRequestObject.TempItemID = localId;
    //writeMessage("AddNewReminderToServer", "Local id in ajax object : " +
    //ajaxRequestObject.TempItemID);
    ajaxRequestObject.MakeRequest();

}

One thing I would like to stay focused on is parameterString. I customized Body request in JSON Format because Ajax request header is in JSON format. So it will only accept JSON string in body.

JavaScript
this.xmlHttp.setRequestHeader("Content-type", "application/json");
 this.xmlHttp.send(this.ParemeterString)

Here, function (responseText) is used as a callback function which will call once response is handed over by the Ajax request call. ResponseText is the result state when response sends back from the server in readystate 4 with status 200.

Now call:

JavaScript
function getDataFromthroughClass() {
    var objSync = new AuthenticateLogin();
    //string name, string email, string phoneNo, string gender, string country)
    var name = document.getElementById("name").value;
    var email = document.getElementById("email").value;
    var phone = document.getElementById("phone").value;
    var language = document.getElementById("language").value;
    var gender = document.getElementById("gender").value;
    var country = document.getElementById("country").value;
    objSync.SendDetailsToServer(new Array(
                                new Array("name", name),
                                new Array("email", email),
                                new Array("language", language),
                                new Array("phoneno", phone),
                                new Array("gender", gender),
                                new Array("country", country),
                                new Array("image", y)));
}

Login Form

This section is pretty interesting and something different which I got from mattiasdanielsson. He gives a nice way to use web id as an authentication by using the drag and drop feature of HTML5.

What we used in login form when the user wants to authenticate, he drops a file (i.e. “xyz.webid”) in the form, which is then read and parsed by JavaScript as JSON. Using jQuery, the users data (name, gender, etc.) is displayed in the drop zone, providing visual feedback to the user. If the file is parsed without error, an input is shown where the user enters his four-digit PIN number. The JavaScript then uses the PIN together with the “authstring in the dropped file to create the key sent to the server... In this demo application, I don't use PIN authentication from server.

JavaScript
var objData;

	$(document).ready(function() {

	    var $droptarget = $('#idBox'), $idCardSrc = $('#idCardSrc'),
				$idBoxBg = $('#idBoxBg'),
		$pinBox = $('#pinBox'), $pinInput = $('input', $pinBox);

	    $droptarget.bind('dragenter', function(e) {
	        e.stopPropagation();
	        e.preventDefault();
	        $droptarget.addClass('drophover');
	        $idBoxBg.text('Drop it now');
	        return false;
	    });
	    $droptarget.bind('dragleave', function(e) {
	        e.stopPropagation();
	        e.preventDefault();
	        $droptarget.removeClass('drophover');
	        $idBoxBg.text('Drop ID file here');
	        return false;
	    });
	    $droptarget.bind('dragover', function(e) {
	        e.stopPropagation();
	        e.preventDefault();
	    });
	    document.getElementById('idBox').addEventListener('drop', function(e) {
	        e.stopPropagation();
	        e.preventDefault();

For drag and drop of webid, we are required to add event handlers to all four events, and use both stopPropagation and preventDefault on them. Otherwise, your browser will just display the dropped file, and never fire the drop event. Also note that jQuery’s bind() method is used with the first three handlers, but not the fourth. Since jQuery doesn’t support the Event.dataTransfer object, we have to bind the drop event using native JavaScript.

Conclusion

I hope you will enjoy this different authentication login window by the magic of HTML5. As I stated from the outset, we can enhance this login authentication in a more logical way for very secure sites by the following method:

  1. You can match base 64 image for validation.
  2. Pin could be hashed in webid or just drop this pin in mail along with attachment of webid.
  3. Encrypt webid (In this demo application, I did not used encryption.)

That's all about the application. For more details, please use the discussion panel.

History

  • 22nd December, 2010: Initial version
  • 22nd March, 2011: Updated article

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)