我在visual studio 2013中创建了一个新的Web窗体项目,我希望用户能够使用他们的用户名(例如管理员)而不是电子邮件地址登录。
如果你打开自动生成的"Register.aspx.cs"文件,你会看到这段代码:
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var user = new ApplicationUser() { UserName = Email.Text, Email = Email.Text };
问题:为什么最后一行的用户名和电子邮件的值相同???在这种情况下,既然已经有了"电子邮件"列,为什么还需要"用户名"列?
是否可以使用用户名而不是电子邮件地址登录
我正试图通过在注册表中添加一个名为"用户名"的新文本框字段来解决这个问题:
Register.aspx
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="UserName" CssClass="col-md-2 control-label">UserName</asp:Label>
<div class="col-md-10">
<asp:TextBox runat="server" ID="UserName" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="Email"
CssClass="text-danger" ErrorMessage="The UserName field is required." />
</div>
</div>
在注册功能上,我做了这样的改变:
Register.aspx.cs
var user = new ApplicationUser() { UserName = UserName.Text, Email = Email.Text };
然后我更改了登录功能,如下所示:
登录.aspx.cs
protected void LogIn(object sender, EventArgs e)
{
if (IsValid)
{
// Validate the user password
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signinManager = Context.GetOwinContext().GetUserManager<ApplicationSignInManager>();
// This doen't count login failures towards account lockout
// To enable password failures to trigger lockout, change to shouldLockout: true
//var result = signinManager.PasswordSignIn(Email.Text, Password.Text, false, shouldLockout: false);
SignInStatus result = SignInStatus.Failure;
// check too see if the user has entered a email address or not
if (IsValidEmail(NameOrEmail.Text))
{
result = signinManager.PasswordSignIn(NameOrEmail.Text, Password.Text, false, shouldLockout: false);
}
else
{
// get users email using his name
var user = manager.FindByName(NameOrEmail.Text);
result = signinManager.PasswordSignIn(user.Email, Password.Text, false, shouldLockout: false);
}
switch (result)
{
case SignInStatus.Success:
string queryString = Request.QueryString["ReturnUrl"];
if (!string.IsNullOrEmpty(queryString))
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
else
Response.Redirect("/Account/Dashboard");
break;
case SignInStatus.LockedOut:
Response.Redirect("/Account/Lockout");
break;
case SignInStatus.Failure:
default:
FailureTextLabel.Text = "Invalid login!";
ErrorMessage.Visible = true;
break;
}
}
}
// check email address
private bool IsValidEmail(string strIn)
{
// Return true if strIn is in valid e-mail format.
return Regex.IsMatch(strIn, @"^([w-.]+)@(([[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.)|(([w-]+.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(]?)$");
}
模板看起来是这样的:
Login.aspx
<div class="form-group">
<asp:Label runat="server" AssociatedControlID="NameOrEmail" CssClass="col-md-2 control-label">UserName or Email</asp:Label>
<div class="col-md-10">
<asp:TextBox runat="server" ID="Email" CssClass="form-control" />
<asp:RequiredFieldValidator runat="server" ControlToValidate="NameOrEmail"
CssClass="text-danger" ErrorMessage="The name or email field is required." />
</div>
</div>
问题:如果您在注册时更改用户名,则无法再登录(您将获得SignInStatus.Failure)。在我看来,用户名必须与注册时的电子邮件相同才能登录。
有办法解决这个问题吗?
首先,这根本不是一个bug。这就是它的工作原理,如果你想使用开箱即用的默认实现,它是用visualstudio2013模板创建的(与个人用户一起),那么你就会得到它。
作为开发人员,asp.net身份信息可以根据我们的选择进行配置。为此,您需要深入身份框架并了解它是如何工作的。
如果您使用了visual studio 2013的更新3或更高版本,则可以在IdentityConfig.cs文件中找到大多数简单但非常重要的配置。
身份框架版本1只提供了用户名,没有支持UI的电子邮件地址,但随着版本2.x和visualstudio2013更新3和4的出现,情况发生了变化,其中包括用户名和电子邮件的电子邮件地址。
您可以将其更改为使用用户名而不是电子邮件,如下所述。
新的开箱即用注册码是:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href="" + callbackUrl + "">here</a>");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
您可以看到用户名和电子邮件都使用模型。电子邮件
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
按如下方式更新您的代码
注册方法
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
UserManager.UserValidator = new UserValidator<ApplicationUser>(UserManager)
{
RequireUniqueEmail = false,
};
var user = new ApplicationUser { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href="" + callbackUrl + "">here</a>");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
RegisterViewModel
public class RegisterViewModel
{
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
LoginViewModel
public class LoginViewModel
{
[Required]
[Display(Name = "UserName")]
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; }
}
此外,您需要更新其他视图模型,不要使用电子邮件,而是使用用户名
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
然后更新所有视图以使用用户名,而不是像下面这样发送电子邮件。
@model WebApplication2.Models.RegisterViewModel
@{
ViewBag.Title = "Register";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
@Html.ValidationSummary("", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}