我正在构建成员唯一的ASP.NET MVC网站,该网站将为其用户提供多种使用FormsAuthentication
登录的方式。因此,我们的想法是,只有一种表格可以进行典型的用户名和密码验证,然后是另一种表格,用于电子证书验证的手机号码。
现在我已经阅读了很多关于如何在一个视图中解决多个表单的文档,现在我有一个相当优雅的解决方案,即一个视图包含两个包含表单的部分视图和一个具有两个模型属性的viewmodel。这为验证提供了一个很好的解决方案,因此每个表单都可以单独验证,而不是在按下相应的提交按钮时进行验证。
以下是代码:
Login.cshtml:
@model OneMeetingPortal2.Models.ViewModel
@{
ViewBag.Title = "Login";
}
<div class="container">
<div class="well">
<h1>@ViewBag.Title.</h1>
</div>
@Html.Partial("_LoginUsernamePasswordPartial", Model.UserPass)
@Html.Partial("_LoginMobilePartial", Model.Mobile)
</div>
_LoginUsernamePasswordPartial.cshtml:
@model OneMeetingPortal2.Models.LoginUsernamePasswordModel
@using (Html.BeginForm("Login", "Account", FormMethod.Post, new { @class = "form-horizontal", @role = "form", @id = "_userNameForm" }))
{
@Html.AntiForgeryToken()
//Birtingu validation elements er stjórnað með CSS. Sjá .validation-summary-valid í Main.css. Birtist ef villa kemur fram.
@Html.ValidationSummary("Eftirfarandi villur komu upp:", new { @class = "alert alert-danger col-sm-offset-2 col-sm-10" })
<div class="form-group">
@Html.LabelFor(m => m.UserName, new { @class = "control-label col-sm-2" })
<div class="col-sm-10">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.UserName)
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Password, new { @class = "control-label col-sm-2" })
<div class="col-sm-10">
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.Password)
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
}
_LoginMobilePartial.cshtml。请注意,如果我将动作名称参数更改为Login
,则会收到有关动作名称的错误消息:
@model OneMeetingPortal2.Models.LoginMobileModel
@using (Html.BeginForm("LoginM", "Account", FormMethod.Post, new { @class = "form-horizontal", @role = "form", @id = "_GSMForm" }))
{
@Html.AntiForgeryToken()
@Html.ValidationSummary("Eftirfarandi villur komu upp:", new { @class= "alert alert-danger col-sm-offset-2 col-sm-10" })
<div class="form-group">
@Html.LabelFor(m => m.MobileNumber, new { @class = "control-label col-sm-2" })
<div class="col-sm-10">
@Html.TextBoxFor(m => m.MobileNumber, new { @class = "form-control" })
@Html.ValidationMessageFor(m => m.MobileNumber)
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<input type="submit" value="Log in" class="btn btn-default" />
</div>
</div>
}
以下是模特:
public class ViewModel
{
public LoginMobileModel Mobile { get; set; }
public LoginUsernamePasswordModel UserPass { get; set; }
}
public class LoginUsernamePasswordModel
{
[Required(ErrorMessage="Ekki má sleppa notandanafni.")]
[Display(Name = "Notandanafn")]
[StringLength(50, ErrorMessage = "Notandanafnið má ekki vera lengra en 50 stafir")]
[MinLength(3, ErrorMessage = "Notandanafnið verður að vera a.m.k. 3 stafir")]
public string UserName { get; set; }
[Required(ErrorMessage="Ekki má sleppa lykilorði.")]
[DataType(DataType.Password)]
[Display(Name = "Lykilorð")]
[StringLength(50, ErrorMessage="Lykilorðið má ekki vera lengra en 50 stafir")]
[MinLength(3, ErrorMessage="Lykilorðið verður að vera a.m.k. 3 stafir")]
public string Password { get; set; }
}
public class LoginMobileModel
{
[Required(ErrorMessage = "Ekki má sleppa símanúmeri.")]
[Display(Name = "Farsímanúmer")]
[StringLength(7, ErrorMessage = "Símanúmer má ekki vera lengra en 7 stafir.")]
[MinLength(7, ErrorMessage = "Símanúmer má ekki vera styttra en 7 stafir.")]
public string MobileNumber { get; set; }
}
然后是Controller方法:
// GET: /Account/Login
[HttpGet]
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
ViewModel m = new ViewModel();
m.Mobile = new LoginMobileModel();
m.UserPass = new LoginUsernamePasswordModel();
return View(m);
}
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginUsernamePasswordModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (_accountService.Login(model.UserName, model.Password))
{
string xmlString = _accountService.GetEmployeeDetails(model.UserName);
Session.Add("ProfileXml", xmlString);
Classes.Profile profile = new Classes.Profile(xmlString);
FormsAuthentication.RedirectFromLoginPage(profile.Subject, false);
}
}
// If we got this far, something failed, redisplay form
ViewModel m = new ViewModel();
m.UserPass = model;
m.Mobile = new LoginMobileModel();
return View(m);
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult LoginM(LoginMobileModel model, string returnUrl)
{
if (ModelState.IsValid)
{
MobileLoginReturn mlr = _accountService.LoginGSM(model.MobileNumber);
if(mlr.Error == null)
{
Session.Add("ProfileXml", mlr.EmployeeXmlString);
Classes.Profile profile = new Classes.Profile(mlr.EmployeeXmlString);
FormsAuthentication.RedirectFromLoginPage(profile.Subject, false);
}
else
{
ModelState.AddModelError("", mlr.Error.Message);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
然而,我得到了一个似乎只与登录页面相关的奇怪行为。我想有两个不同的动作方法LoginUserPass
和LoginMobile
,但我不能。如果我这样命名它们就不会被调用。有趣的是,当我在身份验证后在网站的其他地方设置相同的方案时,例如在Home控制器中一切正常,我可以根据部分视图中的动作名称参数在控制器中调用不同的动作方法,例如我可以有:
@using (Html.BeginForm("LoginMobile", "Account", FormMethod.Post, new { @class = "form-horizontal", @role = "form", @id = "_GSMForm" }))
{
[Code omitted]
}
和
public ActionResult LoginMobile(LoginMobileModel model, string returnUrl){ ... }
在控制器中。
所以,现在,我必须让其中一个部分视图中的第一个参数名称为Login,以便调用Login操作方法。在控制器中只能有两个带有该名称的方法,一个用于get,一个用于post,如果更多,我会得到模糊的方法异常。所以目前我面临的事实是,我必须选择是否要让用户使用手机号码或用户名和密码登录,因为我无法在登录页面上同时使用这两种方法。那当然是不可接受的,当然有两种方法可以,对吗?
我希望有人知道如何解决这个难题。这是否与FormsAuthentication有关?
答案 0 :(得分:0)
当我最终发现导致此行为的是FormsAuthentication时,我找到了答案here
简而言之,从<authorization>
删除web.config
节点,然后在FilterConfig.cs
中添加filters.Add(new AuthorizeAttribute());