65.9K
CodeProject is changing. Read more.
Home

Implement Facebook Login with OpenID Selector in MVC3

Sep 3, 2012

CPOL

2 min read

viewsIcon

24710

How to use the OpenId selector tool in an ASP.NET MVC3 application

In my last post, I explained how we can implement Facebook login with OpenId selector tool. In this post, I will explain how we can use that tool in an ASP.NET MVC3 application.

  1. Open Visual Studio 2010 go to File > New > Project > Web > ASP.NET MVC 3 application:

    Then choose Internet Application. Be sure to have Razor as your View engine and click OK:

  2. Download DotNetOpenAuth DLL and Updated OpenID Selector files that we will use.
    1. Add the DotNetOpenAuth.dll to references in your site.
    2. Copy all contents of openid-selector\css folder to the 'Content' folder.
    3. Copy images, images.large, images.small folders to the site 'Content' folder.
    4. Copy openid-jquery.js, openid-en.js files from openid-selector\js folder to 'Scripts' folder.

    Your Solution Explorer will look like this (see the highlighted portion):

  3. Go to Views > Shared > _Layout.cshtml and replace the <head> with this new head with new styles and scripts:
    <head>
        <meta charset="utf-8" />
        <title>@ViewBag.Title</title>
        <link href="@Url.Content("~/Content/Site.css")" 
        rel="stylesheet" type="text/css" />
        <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" 
        type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/modernizr-1.7.min.js")" 
        type="text/javascript"></script>
        <link href="@Url.Content("~/Content/openid-shadow.css")" 
        rel="stylesheet" type="text/css" />
        <link href="@Url.Content("~/Content/openid.css")" 
        rel="stylesheet" type="text/css" />
        <script src="@Url.Content("~/Scripts/openid-jquery.js")" 
        type="text/javascript"></script>
        <script src="@Url.Content("~/Scripts/openid-en.js")" 
        type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" 
    type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" 
    type="text/javascript"></script>
     <script type="text/javascript" 
     src="https://connect.facebook.net/en_US/all.js"> </script>
       
        <script type="text/javascript">
            $(document).ready(function () {
                openid.init('openid_identifier');
            });
        </script>
    </head>
  4. Go to Models > AccountModels.cs, navigate to public class LogOnModel and Add OpenID attribute that we will use to hold the returned OpenID from OpenID-Selector.

    Your class will look like this:

        public class LogOnModel
        {
            [Display(Name = "OpenID")]
            public string OpenID { get; set; }
    
            [Required]
            [Display(Name = "User name")]
            public string UserName { get; set; }
    
            [Required]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }
    
            [Display(Name = "Remember me?")]
            public bool RememberMe { get; set; }
        }
  5. Go to Models > AccountModels.cs and add the following class to it:
        public class UserDetailsModel
        {
            public string OpenID { get; set; }
            public string ProviderUrl { get; set; }
            public string FriendlyIdentifier { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }        
            public string Dob { get; set; }
            public string Gender { get; set; }
            public string Email { get; set; }
        }
  6. Go to Views > Account > LogOn.cshtml. Replace all the markup with this one. This will integrate updated OpenID-Selector to LogOn View:
    @model FBOpenIDMVC3.Models.LogOnModel
    
    @{
        ViewBag.Title = "Log On";    
    }
    <h2>
        Log On</h2>
    <p>
        Please enter your username and password. 
        @Html.ActionLink("Register", "Register")
        if you don't have an account.
    </p>
    <script type="text/javascript">
        $(document).ready(function () {
            // Init the SDK upon load
            window.fbAsyncInit = function () {
                FB.init({
                    appId: '188220747944294', // App ID
                    channelUrl: '//' + window.location.hostname + 
                    '/channel', // Path to your Channel File
                    scope: 'id,name,first_name,last_name,gender,email',
                    status: true, // check login status
                    cookie: true, // enable cookies to allow the server to access the session
                    xfbml: true   // parse XFBML
                });
            };
        });
        /*This Method will be invoked on lick on Facebook button*/
        function FBLogin() {
            FB.login(FBCallBack);
        }
        function FBCallBack(response) {
            if (response.authResponse) {
                // user has auth'd your app and is logged into Facebook
                FB.api('/me?fields=id,name,first_name,
                last_name,gender,email,birthday', function (userDetail) {
                    if (userDetail.name) {
                        var url = '@Url.Action("ShowUserDetails", 
                        "Account", new { OpenID = "_id_", 
                        FriendlyIdentifier = "_id_", 
                        FirstName = "_first_", LastName = "_last_", 
                        Dob = "_birthday_", Gender = 
                        "_gender_", Email = "_email_" })';
                        url = url.replace('_id_', userDetail.id);
                        url = url.replace('_id_', userDetail.id);
                        url = url.replace('_first_', userDetail.first_name);
                        url = url.replace('_last_', userDetail.last_name);
                        url = url.replace('_birthday_', userDetail.birthday);
                        url = url.replace('_gender_', userDetail.gender);
                        url = url.replace('_email_', userDetail.email);
                        window.location.href = url;
                    }
                });
            }
        }
        </script>  
    <form action="Authenticate?ReturnUrl=@HttpUtility.UrlEncode
    (Request.QueryString["ReturnUrl"])" 
    method="post" id="openid_form">
    <input type="hidden" name="action" value="verify" />
    <div>    
        <fieldset>
            <legend>Login using OpenID</legend>
            <div class="openid_choice">
                <p>
                    Please click your account provider:</p>
                <div id="openid_btns">
                </div>
            </div>
            <div id="openid_input_area">
                @Html.TextBox("openid_identifier")
                <input type="submit" value="Log On" />
            </div>
            <noscript>
                <p>
                    OpenID is service that allows you to 
                    log-on to many different websites using a single
                    indentity. Find out 
                    <a href="http://openid.net/what/">more about OpenID</a> and
                    <a href="http://openid.net/get/">how 
                    to get an OpenID enabled account</a>.</p>
            </noscript>
            <div>
                @if (Model != null)
                {
                    if (String.IsNullOrEmpty(Model.UserName))
                    {
                    <div class="editor-label">
                        @Html.LabelFor(model => model.OpenID)
                    </div>
                    <div class="editor-field">
                        @Html.DisplayFor(model => model.OpenID)
                    </div>
                    <p class="button">
                        @Html.ActionLink("New User ,Register", 
                        "Register", new { OpenID = Model.OpenID })
                    </p>
                    }
                    else
                    {
                        //user exist 
                    <p class="buttonGreen">
                        <a href="@Url.Action("Index", 
                        "Home")">Welcome , @Model.UserName, Continue..." </a>
                    </p>
                    }
                }
            </div>
        </fieldset>
    </div>
    </form>
    
    @Html.ValidationSummary(true, "Login was unsuccessful. 
    Please correct the errors and try again.")
    @using (Html.BeginForm())
    {
        <div>
            <fieldset>
                <legend>Or Login Normally</legend>
                <div class="editor-label">
                    @Html.LabelFor(m => m.UserName)
                </div>
                <div class="editor-field">
                    @Html.TextBoxFor(m => m.UserName)
                    @Html.ValidationMessageFor(m => m.UserName)
                </div>
                <div class="editor-label">
                    @Html.LabelFor(m => m.Password)
                </div>
                <div class="editor-field">
                    @Html.PasswordFor(m => m.Password)
                    @Html.ValidationMessageFor(m => m.Password)
                </div>
                <div class="editor-label">
                    @Html.CheckBoxFor(m => m.RememberMe)
                    @Html.LabelFor(m => m.RememberMe)
                </div>
                <p >
                    <input type="submit" value="Log On" />
                </p>
            </fieldset>
        </div>
    }
  7. Update the value of img_path in openid-jquery.js to '../Content/images/'.
  8. Now let us run the project, then click the [Log On] link, you will get something like this page:

  9. Now to implement Open ID using DotnetOpenAuth, Go to Controllers > AccountController.cs and add these usings:
    using DotNetOpenAuth.Messaging;
    using DotNetOpenAuth.OpenId;
    using DotNetOpenAuth.OpenId.RelyingParty;
    using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;

    Then, add the following code to AccountController.cs:

            private static OpenIdRelyingParty openid = new OpenIdRelyingParty();
    
            [ValidateInput(false)]
            public ActionResult Authenticate(string returnUrl)
            {
                var response = openid.GetResponse();
                if (response == null)
                {
                    //Let us submit the request to OpenID provider
                    Identifier id;
                    if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
                    {
                        try
                        {
                            var request = openid.CreateRequest
                            (Request.Form["openid_identifier"]);
                            var fetch = new FetchRequest();
                            fetch.Attributes.Add(new AttributeRequest
                            (WellKnownAttributes.Contact.Email, true));
                            fetch.Attributes.Add(new AttributeRequest
                            (WellKnownAttributes.BirthDate.WholeBirthDate, true));
                            fetch.Attributes.Add(new AttributeRequest
                            (WellKnownAttributes.Person.Gender, true));
                            fetch.Attributes.Add(new AttributeRequest
                            (WellKnownAttributes.Name.First, true));
                            fetch.Attributes.Add(new AttributeRequest
                            (WellKnownAttributes.Name.Last, true));
                            request.AddExtension(fetch);
                            return request.RedirectingResponse.AsActionResult();
                        }
                        catch (ProtocolException ex)
                        {
                            ViewBag.Message = ex.Message;
                            return View("LogOn");
                        }
                    }
    
                    ViewBag.Message = "Invalid identifier";
                    return View("LogOn");
                }
    
                //Let us check the response
                switch (response.Status)
                {
    
                    case AuthenticationStatus.Authenticated:
                        var fetch = response.GetExtension<FetchResponse>();
                        var sFirstName = "";
                        var sEmail = "";
                        var sLastName = "";
                        var sGender = "";
                        var sDob = "";
                        if (fetch != null)
                        {
                            foreach (var vAtrrib in fetch.Attributes)
                            {
                                switch (vAtrrib.TypeUri)
                                {
                                    case WellKnownAttributes.Name.First:
                                        var firstNames = fetch.Attributes
                                        [WellKnownAttributes.Name.First].Values;
                                        sFirstName = firstNames.Count > 0 ? firstNames[0] : null;
                                        break;
                                    case WellKnownAttributes.Contact.Email:
                                        var emailAddresses = fetch.Attributes
                                        [WellKnownAttributes.Contact.Email].Values;
                                        sEmail = emailAddresses.Count > 0 ? emailAddresses[0] : null;
                                        break;
                                    case WellKnownAttributes.Name.Last:
                                        var lastNames = fetch.Attributes
                                        [WellKnownAttributes.Name.Last].Values;
                                        sLastName = lastNames.Count > 0 ? lastNames[0] : null;
                                        break;
                                    case WellKnownAttributes.Person.Gender:
                                        var genders = fetch.Attributes
                                        [WellKnownAttributes.Person.Gender].Values;
                                        sGender = genders.Count > 0 ? genders[0] : null;
                                        break;
                                    case WellKnownAttributes.BirthDate.WholeBirthDate:
                                        var doBs = fetch.Attributes
                                        [WellKnownAttributes.BirthDate.WholeBirthDate].Values;
                                        sDob = doBs.Count > 0 ? doBs[0] : null;
                                        break;
                                }
                            }
                        }
                        var sFriendlyLogin = response.FriendlyIdentifierForDisplay;
                        var lm = new UserDetailsModel
                        {
                            OpenID = response.ClaimedIdentifier,
                            FriendlyIdentifier = sFriendlyLogin,
                            FirstName = sFirstName,
                            LastName = sLastName,
                            Dob = sDob,
                            Gender = sGender,
                            Email = sEmail
                        };
                        FormsService.SignIn(sEmail, false);
                        return View("ShowUserDetails", lm);
    
                    case AuthenticationStatus.Canceled:
                        ViewBag.Message = "Canceled at provider";
                        return View("LogOn");
                    case AuthenticationStatus.Failed:
                        ViewBag.Message = response.Exception.Message;
                        return View("LogOn");
                }
    
                return new EmptyResult();
            }
    
            public ActionResult ShowUserDetails(UserDetailsModel objUserDetails)
            {
                return View(objUserDetails);
            }
            [HttpPost]
            public ActionResult ShowUserDetails(string OpenID, 
            string FriendlyIdentifier, string FirstName, string LastName, 
            string Dob, string Gender, string Email)
            {
                var objUserDetails = new UserDetailsModel()
                {
                    OpenID = OpenID,
                    FriendlyIdentifier = FriendlyIdentifier,
                    FirstName = FirstName,
                    LastName = LastName,
                    Dob = Dob,
                    Gender = Gender,
                    Email = Email,
                };
                return View(objUserDetails);
            }
  10. Right click on Views--> Accounts and click Add-->View to add new view like this:

  11. Add the following code in this View:
        public class UserDetailsModel
        {
            public string OpenID { get; set; }
            public string ProviderUrl { get; set; }
            public string FriendlyIdentifier { get; set; }
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public string Dob { get; set; }
            public string Gender { get; set; }
            public string Email { get; set; }
        }
  12. Now run the project click [Log On] link and click a provider like Google. It may ask you to sign in or ask you to allow access to your information. You will get a page like this:

Congratulations! Now you have integrated OpenID login with Facebook login to your project.