你的位置:首页 > 软件开发 > ASP.net > 定制Asp.NET 5 MVC内建身份验证机制

定制Asp.NET 5 MVC内建身份验证机制

发布时间:2015-12-21 14:00:15
背景在需要进行表单认证的Asp.NET 5 MVC项目被创建后,往往需要根据项目的实际需求做一系列的工作对MVC 5内建的身份验证机制(Asp.NET Identity)进行扩展和定制:Asp.NET内建的身份验证机制会使用Local DB(本地数据库)读写用户相关的信息,而在数 ...

背景

在需要进行表单认证的Asp.NET 5 MVC项目被创建后,往往需要根据项目的实际需求做一系列的工作对MVC 5内建的身份验证机制(Asp.NET Identity)进行扩展和定制:

  • Asp.NET内建的身份验证机制会使用Local DB(本地数据库)读写用户相关的信息,而在数据库驱动的项目中,管理业务信息的数据库通常是特定的数据库环境,比如远程SQL Server数据库实例或Access数据库等等,业务数据库中保存着一系列针对业务需求的数据表,因此需要定制MVC 5内建身份验证,使其操作的的用户表们与业务数据库的表们共处在同一数据库中
  • Asp.NET身份验证默认创建的用户表名为:AspNetRoles, AspNetUserClaims, AspNetUserLogins, AspNetUserRoles, AspNetUsers等,与实际业务数据库中自成体系的数据表命名习惯(如tblProduct, PRODUCT, Products...)不一致,因此需要定制MVC 5内建身份验证,使其使用我们指定的表名称保存用户信息,以便与实际业务数据库中的表名称处于相同的命名规范体系
  • 实际业务中用户信息往往多于Asp.NET默认提供的,如根据实际情况会需要以用户email登录,或在Users表中保存用户的guid,性别,地址,是否激活等等,因此需要对Asp.net创建的表,以及相应操作的代码进行扩展

总之,一切都是为了减轻管理的负担,提升工作效率,使项目整体变得更加优雅。

要点

本文仅聚焦在表单身份认证(Forms Authentication)的个性化定制

   

Step 6. 在类库项目中创建Models

  6.1 创建Models文件夹
    该文件夹用于保存用户验证相关的模型类,这些类都继承自Microsoft.AspNet.Identity.EntityFramework命名空间下相应的类,并显示指定了关键字的类型为long(Asp.NET默认使用get='_blank'>string类型)

Step 12. 接下来是Controller, 打开MVC项目下Controllers文件夹中的AccountController.cs,修改后的文件如下所示

定制Asp.NET 5 MVC内建身份验证机制定制Asp.NET 5 MVC内建身份验证机制
using System;using System.Threading.Tasks;using System.Web;using System.Web.Mvc;using Core.Models;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Microsoft.Owin.Security;using MyMvcProject.Models;namespace MyMvcProject.Controllers{  [Authorize]  public class AccountController : Controller  {    #region constants    private const string XsrfKey = "XsrfId";    #endregion    #region member vars    private MyUserManager _userManager;    #endregion    #region enums    public enum ManageMessageId    {      ChangePasswordSuccess,      SetPasswordSuccess,      RemoveLoginSuccess,      Error    }    #endregion    #region properties    public MyUserManager UserManager    {      get      {        return _userManager ?? HttpContext.GetOwinContext().GetUserManager<MyUserManager>();      }      private set      {        _userManager = value;      }    }    private IAuthenticationManager AuthenticationManager    {      get      {        return HttpContext.GetOwinContext().Authentication;      }    }    #endregion    #region constructors and destructors    public AccountController()    {    }    public AccountController(MyUserManager userManager)    {      UserManager = userManager;    }    protected override void Dispose(bool disposing)    {      if (disposing && UserManager != null)      {        UserManager.Dispose();        UserManager = null;      }      base.Dispose(disposing);    }    #endregion    #region methods    [AllowAnonymous]    public async Task<ActionResult> ConfirmEmail(long userId, string code)    {      if (userId == null || code == null)      {        return View("Error");      }      var result = await UserManager.ConfirmEmailAsync(userId, code);      if (result.Succeeded)      {        return View("ConfirmEmail");      }      AddErrors(result);      return View();    }    //    // POST: /Account/Disassociate    [HttpPost]    [ValidateAntiForgeryToken]    public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)    {      ManageMessageId? message = null;      var result = await UserManager.RemoveLoginAsync(long.Parse(User.Identity.GetUserId()), new UserLoginInfo(loginProvider, providerKey));      if (result.Succeeded)      {        var user = await UserManager.FindByIdAsync(long.Parse(User.Identity.GetUserId()));        await SignInAsync(user, false);        message = ManageMessageId.RemoveLoginSuccess;      }      else      {        message = ManageMessageId.Error;      }      return RedirectToAction(        "Manage",        new        {          Message = message        });    }    //    // POST: /Account/ExternalLogin    [HttpPost]    [AllowAnonymous]    [ValidateAntiForgeryToken]    public ActionResult ExternalLogin(string provider, string returnUrl)    {      // Request a redirect to the external login provider      return new ChallengeResult(        provider,        Url.Action(          "ExternalLoginCallback",          "Account",          new          {            ReturnUrl = returnUrl          }));    }    //    // GET: /Account/ExternalLoginCallback    [AllowAnonymous]    public async Task<ActionResult> ExternalLoginCallback(string returnUrl)    {      var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();      if (loginInfo == null)      {        return RedirectToAction("Login");      }      // Sign in the user with this external login provider if the user already has a login      var user = await UserManager.FindAsync(loginInfo.Login);      if (user != null)      {        await SignInAsync(user, false);        return RedirectToLocal(returnUrl);      }      // If the user does not have an account, then prompt the user to create an account      ViewBag.ReturnUrl = returnUrl;      ViewBag.LoginProvider = loginInfo.Login.LoginProvider;      return View(        "ExternalLoginConfirmation",        new ExternalLoginConfirmationViewModel        {          Email = loginInfo.Email        });    }    //    // POST: /Account/ExternalLoginConfirmation    [HttpPost]    [AllowAnonymous]    [ValidateAntiForgeryToken]    public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)    {      if (User.Identity.IsAuthenticated)      {        return RedirectToAction("Manage");      }      if (ModelState.IsValid)      {        // Get the information about the user from the external login provider        var info = await AuthenticationManager.GetExternalLoginInfoAsync();        if (info == null)        {          return View("ExternalLoginFailure");        }        var user = new MyUser        {          UserName = model.Email,          Email = model.Email        };        var result = await UserManager.CreateAsync(user);        if (result.Succeeded)        {          result = await UserManager.AddLoginAsync(user.Id, info.Login);          if (result.Succeeded)          {            await SignInAsync(user, 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);            // SendEmail(user.Email, callbackUrl, "Confirm your account", "Please confirm your account by clicking this link");            return RedirectToLocal(returnUrl);          }        }        AddErrors(result);      }      ViewBag.ReturnUrl = returnUrl;      return View(model);    }    //    // GET: /Account/ExternalLoginFailure    [AllowAnonymous]    public ActionResult ExternalLoginFailure()    {      return View();    }    [AllowAnonymous]    public ActionResult ForgotPassword()    {      return View();    }    //    // POST: /Account/ForgotPassword    [HttpPost]    [AllowAnonymous]    [ValidateAntiForgeryToken]    public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)    {      if (ModelState.IsValid)      {        var user = await UserManager.FindByNameAsync(model.Email);        if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))        {          ModelState.AddModelError("", "The user either does not exist or is not confirmed.");          return View();        }        // 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.GeneratePasswordResetTokenAsync(user.Id);        // var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);            // await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>");        // return RedirectToAction("ForgotPasswordConfirmation", "Account");      }      // If we got this far, something failed, redisplay form      return View(model);    }    //    // GET: /Account/ForgotPasswordConfirmation    [AllowAnonymous]    public ActionResult ForgotPasswordConfirmation()    {      return View();    }    //    // POST: /Account/LinkLogin    [HttpPost]    [ValidateAntiForgeryToken]    public ActionResult LinkLogin(string provider)    {      // Request a redirect to the external login provider to link a login for the current user      return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId());    }    //    // GET: /Account/LinkLoginCallback    public async Task<ActionResult> LinkLoginCallback()    {      var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());      if (loginInfo == null)      {        return RedirectToAction(          "Manage",          new          {            Message = ManageMessageId.Error          });      }      var result = await UserManager.AddLoginAsync(long.Parse(User.Identity.GetUserId()), loginInfo.Login);      if (result.Succeeded)      {        return RedirectToAction("Manage");      }      return RedirectToAction(        "Manage",        new        {          Message = ManageMessageId.Error        });    }    //    // POST: /Account/LogOff    [HttpPost]    [ValidateAntiForgeryToken]    public ActionResult LogOff()    {      AuthenticationManager.SignOut();      return RedirectToAction("Index", "Home");    }    //    // 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)      {        var user = await UserManager.FindAsync(model.Email, model.Password);        if (user != null)        {          await SignInAsync(user, model.RememberMe);          return RedirectToLocal(returnUrl);        }        ModelState.AddModelError("", "Invalid username or password.");      }      // If we got this far, something failed, redisplay form      return View(model);    }    //    // GET: /Account/Manage    public ActionResult Manage(ManageMessageId? message)    {      ViewBag.StatusMessage =        message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."        : message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."        : message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."        : message == ManageMessageId.Error ? "An error has occurred."        : "";      ViewBag.HasLocalPassword = HasPassword();      ViewBag.ReturnUrl = Url.Action("Manage");      return View();    }    //    // POST: /Account/Manage    [HttpPost]    [ValidateAntiForgeryToken]    public async Task<ActionResult> Manage(ManageUserViewModel model)    {      var hasPassword = HasPassword();      ViewBag.HasLocalPassword = hasPassword;      ViewBag.ReturnUrl = Url.Action("Manage");      if (hasPassword)      {        if (ModelState.IsValid)        {          var result = await UserManager.ChangePasswordAsync(long.Parse(User.Identity.GetUserId()), model.OldPassword, model.NewPassword);          if (result.Succeeded)          {            var user = await UserManager.FindByIdAsync(long.Parse(User.Identity.GetUserId()));            await SignInAsync(user, false);            return RedirectToAction(              "Manage",              new              {                Message = ManageMessageId.ChangePasswordSuccess              });          }          AddErrors(result);        }      }      else      {        // User does not have a password so remove any validation errors caused by a missing OldPassword field        var state = ModelState["OldPassword"];        if (state != null)        {          state.Errors.Clear();        }        if (ModelState.IsValid)        {          var result = await UserManager.AddPasswordAsync(long.Parse(User.Identity.GetUserId()), model.NewPassword);          if (result.Succeeded)          {            return RedirectToAction(              "Manage",              new              {                Message = ManageMessageId.SetPasswordSuccess              });          }          AddErrors(result);        }      }      // If we got this far, something failed, redisplay form      return View(model);    }    //    // GET: /Account/Register    [AllowAnonymous]    public ActionResult Register()    {      return View();    }    //    // POST: /Account/Register    [HttpPost]    [AllowAnonymous]    [ValidateAntiForgeryToken]    public async Task<ActionResult> Register(RegisterViewModel model)    {      if (ModelState.IsValid)      {        var user = new MyUser        {          UserName = model.Email,          Email = model.Email        };        try        {          var result = await UserManager.CreateAsync(user, model.Password);          if (result.Succeeded)          {            await SignInAsync(user, 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);        }        catch (Exception ex)        {          throw (ex);        }      }      // If we got this far, something failed, redisplay form      return View(model);    }    [ChildActionOnly]    public ActionResult RemoveAccountList()    {      var linkedAccounts = UserManager.GetLogins(long.Parse(User.Identity.GetUserId()));      ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;      return PartialView("_RemoveAccountPartial", linkedAccounts);    }    [AllowAnonymous]    public ActionResult ResetPassword(string code)    {      if (code == null)      {        return View("Error");      }      return View();    }    //    // POST: /Account/ResetPassword    [HttpPost]    [AllowAnonymous]    [ValidateAntiForgeryToken]    public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)    {      if (ModelState.IsValid)      {        var user = await UserManager.FindByNameAsync(model.Email);        if (user == null)        {          ModelState.AddModelError("", "No user found.");          return View();        }        var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);        if (result.Succeeded)        {          return RedirectToAction("ResetPasswordConfirmation", "Account");        }        AddErrors(result);        return View();      }      // If we got this far, something failed, redisplay form      return View(model);    }    //    // GET: /Account/ResetPasswordConfirmation    [AllowAnonymous]    public ActionResult ResetPasswordConfirmation()    {      return View();    }    #endregion    #region Helpers    private async Task SignInAsync(MyUser user, bool isPersistent)    {      AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);      var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);      AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);    }    private void AddErrors(IdentityResult result)    {      foreach (var error in result.Errors)      {        ModelState.AddModelError("", error);      }    }    private bool HasPassword()    {      var user = UserManager.FindById(long.Parse(User.Identity.GetUserId()));      if (user != null)      {        return user.PasswordHash != null;      }      return false;    }    private ActionResult RedirectToLocal(string returnUrl)    {      if (Url.IsLocalUrl(returnUrl))      {        return Redirect(returnUrl);      }      else      {        return RedirectToAction("Index", "Home");      }    }    #endregion    private class ChallengeResult : HttpUnauthorizedResult    {      #region constructors and destructors      public ChallengeResult(string provider, string redirectUri)        : this(provider, redirectUri, null)      {      }      public ChallengeResult(string provider, string redirectUri, string userId)      {        LoginProvider = provider;        RedirectUri = redirectUri;        UserId = userId;      }      #endregion      #region properties      public string LoginProvider { get; set; }      public string RedirectUri { get; set; }      public string UserId { get; set; }      #endregion      #region methods      public override void ExecuteResult(ControllerContext context)      {        var properties = new AuthenticationProperties        {          RedirectUri = RedirectUri        };        if (UserId != null)        {          properties.Dictionary[XsrfKey] = UserId;        }        context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);      }      #endregion    }  }}

Step 15. 试运行MVC项目,网站正常运行后,先注册用户:

  定制Asp.NET 5 MVC内建身份验证机制

Step 16. 检查目标数据库,用户数据已保存至Web.config文件所指定的目标数据库User表中

  定制Asp.NET 5 MVC内建身份验证机制

 

海外公司注册、海外银行开户、跨境平台代入驻、VAT、EPR等知识和在线办理:https://www.xlkjsw.com

原标题:定制Asp.NET 5 MVC内建身份验证机制

关键词:ASP.NET

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。