2015-09-07 51 views
1

我有一个使用内置表单身份验证(与MDF数据库存储在App_data中)的MVC项目。我想将登录表单更改为Ajax登录表单,以便我可以利用“onSuccess”和“onFailure”选项。Ajax从MVC登录

有没有人有我如何实现这个工作的例子,因为我已经尝试过previuosly,但我无法获得表单来验证它只是无所事事。我想我可能错过了一步,所以任何帮助表示赞赏。

示例代码也是人造的。请在下面找到我目前的代码。

登录视图

@model MyProject.Models.LoginViewModel 

@using (Ajax.BeginForm("Login", "Account", null, new AjaxOptions 
    { 
     OnSuccess = "OnSuccess", 
     OnBegin = "OnBegin", 
     OnFailure = "OnFailure", 
     OnComplete = "OnComplete", 
     HttpMethod = "POST", 
     UpdateTargetId = "target" 
    })) 
    { 
     @Html.AntiForgeryToken() 
     @Html.ValidationSummary(true) 
     <fieldset> 
      <legend>Login Form</legend> 
      <ol> 
       <li> 
       @Html.LabelFor(m => m.UserName) 
       @Html.TextBoxFor(m => m.UserName) 
       @Html.ValidationMessageFor(m => m.UserName) 
       </li> 
       <li> 
       @Html.LabelFor(m => m.Password) 
       @Html.PasswordFor(m => m.Password) 
       @Html.ValidationMessageFor(m => m.Password) 
       </li> 
       <li> 
       @Html.CheckBoxFor(m => m.RememberMe) 
       @Html.LabelFor(m => m.RememberMe, new { @class = "checkbox" }) 
       </li> 
      </ol> 
      <input type="submit" value="Login" /> 
      </fieldset> 
} 

这里是登录控制器

[HttpPost] 
    [AllowAnonymous] 
    [ValidateAntiForgeryToken] 
    public JsonResult ValidateUser(string userid, string password, 
            bool rememberme) 
    { 
     LoginStatus status = new LoginStatus(); 
     if (Membership.ValidateUser(userid, password)) 
     { 
      FormsAuthentication.SetAuthCookie(userid, rememberme); 
      status.Success = true; 
      status.TargetURL = FormsAuthentication. 
           GetRedirectUrl(userid, rememberme); 
      if (string.IsNullOrEmpty(status.TargetURL)) 
      { 
       status.TargetURL = FormsAuthentication.DefaultUrl; 
      } 
      status.Message = "Login attempt successful!"; 
     } 
     else 
     { 
      status.Success = false; 
      status.Message = "Invalid UserID or Password!"; 
      status.TargetURL = FormsAuthentication.LoginUrl; 
     } 
     return Json(status); 
    } 

在这里被用于处理形式

在网页上的登录视图模型

public class LoginStatus 
{ 
    public bool Success { get; set; } 
    public string Message { get; set; } 
    public string TargetURL { get; set; } 
} 

脚本

$(document).ready(function() { 
    $("#login").click(function() { 

     $("#message").html("Logging in..."); 

     var data = { 
      "UserName": $("#userid").val(), 
      "Password": $("#password").val(), 
      "RememberMe": $("#rememberme").prop("checked") 
      }; 
     $.ajax({ 
      url: "/Home/Index", 
      type: "POST", 
      data: JSON.stringify(data), 
      dataType: "json", 
      contentType: "application/json", 
      success: function (status) { 
       $("#message").html(status.Message); 
       if (status.Success) 
       { 
        window.location.href = status.TargetURL; 
       } 
      }, 
      error: function() { 
       $("#message").html("Error while authenticating user credentials!"); 
      } 
     }); 
    }); 
}); 
+0

可以显示(OnSuccess)函数的代码吗? – Ala

+0

我已将它添加到最后的阿拉 – Yanayaya

回答

0

我有一个扩展名(MvcNotification)放入ViewData或TempData消息显示。

为了补充这一点,我的帖子操作返回“ERROR”或“OK”,我在ajax窗体OnSuccess中使用这些消息。

消息类型

public enum MessageType 
{ 
    Success, 
    Warning, 
    Error, 
    Info  
} 

AjaxMessagesFilter

/// <summary> 
/// If we're dealing with ajax requests, any message that is in the view  data goes to the http header. 
/// </summary> 
public class AjaxMessagesFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     if (filterContext.HttpContext.Request.IsAjaxRequest()) 
     { 
      var viewData = filterContext.Controller.ViewData; 
      var response = filterContext.HttpContext.Response; 

      foreach (var messageType in Enum.GetNames(typeof(MessageType))) 
      { 
       var message = viewData.ContainsKey(messageType) 
          ? viewData[messageType] 
          : null; 
       if (message != null) // We store only one message in the http header. First message that comes wins. 
       { 
        response.AddHeader("X-Message-Type", messageType.ToLower()); 
        response.AddHeader("X-Message", HttpUtility.HtmlEncode(message.ToString())); 
        return; 
       } 
      } 
     } 
    } 
} 

ControllerExtensions

public static class ControllerExtensions 
{ 
    public static ActionResult ShowMessage(this Controller controller, MessageType messageType, string message, bool showAfterRedirect = false, bool UseJson = false) 
    { 
     var messageTypeKey = messageType.ToString(); 
     if (showAfterRedirect) 
     { 
      controller.TempData[messageTypeKey] = message; 
     } 
     else 
     { 
      controller.ViewData[messageTypeKey] = message; 
     } 

     if (UseJson) 
      return new JsonResult() { Data = "ERROR", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
     else 
      return new ContentResult() { Content = "ERROR" }; 
    } 

    public static ActionResult ShowMessage(this ControllerBase controller, MessageType messageType, string message, bool showAfterRedirect = false, bool UseJson = false) 
    { 
     var messageTypeKey = messageType.ToString(); 
     if (showAfterRedirect) 
     { 
      controller.TempData[messageTypeKey] = message; 
     } 
     else 
     { 
      controller.ViewData[messageTypeKey] = message; 
     } 

     if (UseJson) 
      return new JsonResult() { Data = "ERROR", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
     else 
      return new ContentResult() { Content = "ERROR" }; 
    } 

    public static ActionResult EmptyField(this Controller controller, string FieldName, bool IsJson = false) 
    { 
     controller.ShowMessage(MessageType.Info, String.Format("O campo \"{0}\" é de carácter obrigatório.", FieldName)); 
     return IsJson == false ? (ActionResult)new ContentResult() { Content = "ERROR" } : (ActionResult)new JsonResult() { Data = "ERROR", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; 
    } 
} 

呼叫分机控制器内部:

this.ShowMessage(MessageType.Error, "An error has occurred"); 
如果你想在消息被抛出后重定向

,您需要在最后一个参数添加真。

this.ShowMessage(MessageType.Error, "An error has occurred", true); 

注:我创建了EmptyField方法给一个非标准的消息时,有些字段为空。

操作示例(LoginPost)

[HttpPost] 
[AllowAnonymous] 
public ActionResult LoginPost(LoginViewModel model, string returnUrl, bool Relogin = false) 
{ 
    returnUrl = string.IsNullOrEmpty(returnUrl) || string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl; 

    if (string.IsNullOrEmpty(model.UserName)) 
     return this.EmptyField(Resource_General.UserName); 

    if (string.IsNullOrEmpty(model.Password)) 
     return this.EmptyField(Resource_General.Password); 

    // This doesn't count login failures towards account lockout 
    // To enable password failures to trigger account lockout, change to shouldLockout: true 
    var result = SignInManager.PasswordSignIn(model.UserName, model.Password, model.RememberMe, shouldLockout: false); 

    switch (result) 
    { 
     case SignInStatus.Success: 
      var user = db.Users.FirstOrDefault(x => x.UserName == model.UserName); 

      if (!user.IsActive) 
      { 
       AuthenticationManager.SignOut(); 
       this.ShowMessage(MessageType.Error, Messages.LockedOutUser); 
       return Content("ERROR"); 
      } 

      if (Url.IsLocalUrl(returnUrl)) 
       return Content(returnUrl); 
      else 
       return Content("/Home"); 
     case SignInStatus.LockedOut: 
      this.ShowMessage(MessageType.Error, Messages.LockedOutUser); 
      return Content("ERROR"); 
     case SignInStatus.RequiresVerification: 
     case SignInStatus.Failure: 
     default: 
      this.ShowMessage(MessageType.Error, Messages.WrongPassword); 
      return Content("ERROR"); 
    } 
} 

Ajax的表格

@using (Ajax.BeginForm("LoginPost", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, new AjaxOptions { OnSuccess = "OnSuccess" }, new { @id = "login-form" })) 
{ 
    @Html.AntiForgeryToken() 

    <div class="network-login-fields"> 
     <div class="form-group"> 
      <div class="input-group col-xs-12"> 
       @Html.TextBoxFor(m => m.UserName, new { @class = "form-control", placeholder = Resource_General.UserNamePlaceHolder, name = "loginname", autofocus = "true" }) 
      </div> 
     </div> 

     <div class="form-group"> 
      <div class="input-group col-xs-12"> 
       @Html.PasswordFor(m => m.Password, new { @class = "form-control", placeholder = Resource_General.PasswordPlaceHolder, name = "password" }) 

      </div> 
     </div> 

     <div class="network-login-links"> 
      <button class="btn btn-default"><i class="fa fa-sign-in"></i>&nbsp;@Resource_General.Login</button> 
     </div> 
    </div> 
} 

的Javascript

function OnSuccess(data) { 
    if (data != "ERROR") { 
     window.location.href = data; 
    } 
} 

在JavaScript中,您需要处理ajax表单OnSuccess,并在响应为“OK”或“ERROR”时执行某些操作。

在你的主JavaScript文件,你需要有这样的:

处理消息

// START Messages and Notifications 
function handleAjaxMessages() { 
    $(document).ajaxStart(function() { 
     Openloading(); 
    }).ajaxComplete(function (e, xhr, settings) { 
     CloseLoading(); 
    }).ajaxSuccess(function (event, request) { 
     checkAndHandleMessageFromHeader(request); 
    }).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) { 
     if (thrownError !== "abort") { 
      CloseLoading(); 
      NotifyError(); 
     } 
     OnInit(); 
    }); 
} 

function checkAndHandleMessageFromHeader(request) { 
    var msg = request.getResponseHeader('X-Message'); 
    if (msg) { 
     var title = NotifyHeader(request.getResponseHeader('X-Message-Type')); 
     Notify(msg, title, request.getResponseHeader('X-Message-Type')); 
    } 
} 

function NotifyHeader(type) { 
    console.log(type); 
    var title = ""; 
    if (type == "error") 
     title = CustomScriptsLocales.ErrorTitle; 
    if (type == "success") 
     title = CustomScriptsLocales.SuccessTitle; 
    if (type == "warning") 
     title = CustomScriptsLocales.WarningTitle; 
    if (type == "info") 
     title = CustomScriptsLocales.InfoTitle; 
    console.log(title); 
    return title; 
} 

function Notify(message, title, type) { 
    if (title == null || title == "" || title == undefined) { 
     title = NotifyHeader(type); 
    } 

    PNotify.desktop.permission(); 
    var notice = new PNotify({ 
     title: title, 
     text: decodeHtml(message), 
     nonblock: { 
      nonblock: true, 
      nonblock_opacity: .55 
     }, 
     buttons: { 
      closer: true, 
     }, 
     desktop: { 
      desktop: false, 
     }, 
     hide: true, 
     type: type, 
     delay: 2000, 
     insert_brs: true, 
     remove: true, 
    }); 
} 

function NotifyError() { 
    Notify(CustomScriptsLocales.ErrorMessage, CustomScriptsLocales.ErrorTitle, "error"); 
} 
// END Messages and Notifications 

,并称之为一个现成的函数内部:

$(document).ready(function() { 
    handleAjaxMessages(); 
} 

注:我使用PNotify插件显示通知。如果你不想通知只是排除所有这些JavaScript“处理消息”。