1

i have a login form in a partial view which resides in a modal in the main template (layout). Upon clicking on a button the login form appears and the user should fill that form, till yet everything is just fine but whenever the user clicks the login button the data is sent to the server for validation if the data was fine the user is redirected to website secure area but if not the user is lost because the page has been refreshed and the modal is not shown back so the user has to click back on login to preview the modal and then see the error! I would like to implement an ajax login where when the user clicks on login button if the data is correct should be redirected to website secure area else an error should be given. Here is the partial view for login.

@model Hire.af.WebUI.Models.LoginViewModel



    <!--Login Form-->
        @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "noo-ajax-login-form form-horizontal", role = "form" }))
        {
            @Html.AntiForgeryToken()
            <hr />
            @Html.ValidationSummary(true, "", new { @class = "text-danger" })
            <div class="form-group row">
                <div class="col-sm-9">
                    @Html.TextBoxFor(m => m.Email, new { @class = "log form-control", @placeholder="Email OR Username" })
                    @Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group row">
                @Html.LabelFor(m => m.Password, new { @class = "col-sm-3 control-label" })
                <div class="col-sm-9">
                    @Html.PasswordFor(m => m.Password, new { @class = "pwd form-control", @placeholder="Password" })
                    @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                </div>
            </div>
            <div class="form-group row">
                <div class="col-sm-9 col-sm-offset-3">
                    <div class="checkbox">
                        <div class="form-control-flat">
                            <label class="checkbox">
                                @Html.CheckBoxFor(m => m.RememberMe, new { @class = "rememberme", @type = "checkbox" })
                                <i></i> Remember Me
                            </label>
                        </div>
                    </div>
                </div>
            </div>

             <!--Remember Me Checkbox-->
                <div class="form-actions form-group text-center">
                    <input type="submit" value="Sign In" class="btn btn-primary" />
                    <div class="login-form-links">
                        <span><a href="#"><i class="fa fa-question-circle"></i> Forgot Password?</a></span>
                        <span>
                            Don't have an account yet?
                            <a href="#" class="member-register-link" data-rel="registerModal">
                                @Html.ActionLink("Register Now", "Register") <i class="fa fa-long-arrow-right"></i>
                            </a>
                        </span>
                    </div>
                </div>

            @* Enable this once you have account confirmation enabled for password reset functionality
            <p>
                @Html.ActionLink("Forgot your password?", "ForgotPassword")
            </p>*@
        }

any help would be appreciated. Thanks.

Edit1 for Samit Patel: Here is controller action method for Login

// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
    ViewBag.ReturnUrl = returnUrl;
    return View();
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    // This doesn't count login failures towards account lockout
    // To enable password failures to trigger account lockout, change to shouldLockout: true
    var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
    switch (result)
    {
        case SignInStatus.Success:
            return RedirectToLocal(returnUrl);
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
        case SignInStatus.Failure:
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}
3
  • The real question is why you would do this. A login is a once off per session action, so your every page is now being sent, and rendering, a lot of extra html will will not be needed 99% of the time. Just follow the normal pattern of marking appropriate method with [Authorize] and if the user navigates to it, they will be redirected to your login page, and if successful, then to the page they were navigating to. Commented Mar 16, 2016 at 0:16
  • 1
    @StephenMuecke would you please read the question first?! the question has nothing to do with your comment. i would like to implement ajax login Commented Mar 16, 2016 at 17:56
  • I know exactly what your trying to do! I am questioning why you unnecessarily including the html for a login form in the layout as opposed to loading it dynamically only when its needed. And the whole purpose of ajax is to stay on the same page so all your return RedirectToAction() are pointless since ajax calls will never redirect. Commented Mar 16, 2016 at 22:25

2 Answers 2

5

Really you should be passing a model back and forth to the View and the Controller, hence the term MVC (Model View Controller). I would create a WebLogin.cs model, this way you can verify the state of the model. The biggest issue I have with the above code is that you are including the Anti-Forgery token, but you are not handling it in anyway which makes it pointless to include.

WebLogin{

[Required]
public string Name {get;set;}
[Required]
public string Password {get;set;}
}

Here you can allow HTML, preset the max length of the strings and ton more through Data Annotations and setup some preset error messages to guide the user in case of an error.

See the following: https://msdn.microsoft.com/en-us/library/ee256141(v=vs.100).aspx

On the controller Side:

[HttpGet]
public async Task<ActionResult> AuthenticateUser(){
 return View(new WebLoginModel());
} 

[HttpPost,ValidateAntiforgeryToken]
public async Task<ActionResult> AuthenticateUser(WebLoginModel login){
 //Right here you can flag a model is invalid and return an error to the Jquery
 //AJAX call and handle it directly with HTML. 
 if(!ModelState.Valid)return new HttpStatusCodeResult(HttpstatusCode.Invalid);
   var validLogin = LoginMethodInYourModel( Or whatever else you are using ).
}

In the HTML/Jquery you would do it like this:

<script type="text/javascript">
    $('form').submit(function () {
        var form = $('form'); // This will work if its the only form in the                   
        //view, otherwise use an Id, Name or even a class will work. 
        var token = $('input[name="__RequestVerificationToken"]', form).val();
        var lData = $('form').serialize();
        $.ajax({
            url: $(this).data('url'),
            type: 'POST',
            data: { 
                __RequestVerificationToken: token, 
                WebLoginModel: lData 
            },
            success: function (result) {
                alert(result.someValue);
            },
            error:function(errorResult){
              //You can handle the error gracefully here and allow your user to 
              //know what is going on.
           }
        });
        return false;
    });
</script>

I cannot take all of the credit for this, I actually learned the best way to handle/validate the anti-forgery token from the following post:

include antiforgerytoken in ajax post ASP.NET MVC

By doing it this way with JQuery you can prompt the user with a waiting glass or spinning logo and do some work on the server side and it is clean and to the point.

Sign up to request clarification or add additional context in comments.

Comments

0

Just make the AJAX request on the Button click of Login,

First of all make your Login Button as Button type,

Assign ID to Form

@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "noo-ajax-login-form form-horizontal", role = "form" , @id = "yourID" }))
  { 
}

HTML

<input type="button" id="btnSubmit"/>

Jquery

On Click of btnSubmit this Jquery fire

  $("#btnSubmit").click(function)
    {
        $,ajax({
          url:"Account/Login?Username=" + username + "&pass=" + pass,
          success: function(result)
                 {
                    if(result == "Authenticated")
                     {
                         $("#yourID").submit();
                     }
                    else 
                     {
                         alert("Login Failed");
                     }
                   }
         })
    }

Controller

[HttpGet] 
Public ActionResult CheckAuthentication(string username, string pass)
{
  // Your code to check the Authentication
  int count = _dbcontext.modal.toList(r => r.Username == username && r. password == pass).toList().Count; 
  if(count == 1)
  {
     return JSON("Authenticated",JsonRequestBehaviour.AllowGet);
  }
  else
  {
     return JSON("Failed");
   }
}


[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }
// Remove all this stuff as we could achieve the same in AJAX request
}

2 Comments

Thanks for the answer, seems i still need to do a lot as far as i am new to ajax and mvc would you please make it a bit more clear as my question? if you need me to provide the controller action so please let me know
Yes please provide the Action method of controller

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.