源码在这里:https://github.com/darrenji/UseIdentityCRUDUserInMVC,本地下载
在VS2013中创建一个MVC项目,用默认的”无身份验证”作为身份验证机制。
通过控制台下载Bootstrap。
Install-Package -version 3.0.3 bootstrap
下载成功后,在解决方案下的Content和Scripts多了该版本的css和js文件。
把创建项目默认HomeController中的所有Action以及/Views/Home下的所有视图删除。
热热身
先来做一个简单练习。
在HomeController中的Index方法中,把一个字典传递给视图。
1 2 3 4 5 6 7 8 9 | public class HomeController : Controller { public ActionResult Index() { Dictionary< string object = "" > data = new Dictionary< string object = "" >(); data.Add( "placeholder" , "placeholder" ); return View(data); } }</ string ></ string > |
_Layout.cshtml设置如下:
1 2 3 4 5 6 7 8 9 | < meta charset = "utf-8" >< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >< title >ASP.NET Identity实战</ title >< link href = "~/Content/bootstrap.min.css" rel = "external nofollow" >< link href = "~/Content/bootstrap-theme.min.css" rel = "external nofollow" >< style > .container {padding-top:10px;} .validation-summary-errors{color:red;} </ style >< div class = "container" > @RenderBody() </ div > @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @RenderSection("scripts", required: false) |
Home/Index.cshtml视图中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } < div class = "panel panel-primary" > < div class = "panel-heading" >用户明细</ div > @foreach (string key in Model.Keys) { } < table class = "table table-striped" >< tbody >< tr > < th >@key</ th > < td >@Model[key]</ td > </ tr ></ tbody ></ table > </ div > |
前期准备
分别安装如下组件。
Install-Package Microsoft.AspNet.Identity.EntityFramework –Version 2.0.0
Install-Package Microsoft.AspNet.Identity.OWIN -Version 2.0.0
Install-Package Microsoft.Owin.Host.SystemWeb -Version 2.1.0
配置Web.config如下:
1 | <!--?xml version="1.0" encoding="utf-8"?--> < configuration >< configsections >< section name = "entityFramework" type = "System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirepermission = "false" ></ section ></ configsections >< connectionstrings >< add name = "IdentityDb" providername = "System.Data.SqlClient" connectionstring = "Data Source=(localdb)v11.0;Initial Catalog=IdentityDb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;MultipleActiveResultSets=True" ></ add ></ connectionstrings >< appsettings >< add key = "webpages:Version" value = "3.0.0.0" ></ add >< add key = "webpages:Enabled" value = "false" ></ add >< add key = "ClientValidationEnabled" value = "true" ></ add >< add key = "UnobtrusiveJavaScriptEnabled" value = "true" ></ add >< add key = "owin:AppStartup" value = "WebApplication4.IdentityConfig" ></ add ></ appsettings >< system.web >< compilation debug = "true" targetframework = "4.5" ></ compilation >< httpruntime targetframework = "4.5" ></ httpruntime ></ system.web >< runtime >< assemblybinding xmlns = "urn:schemas-microsoft-com:asm.v1" >< dependentassembly >< assemblyidentity name = "System.Web.Helpers" publickeytoken = "31bf3856ad364e35" ></ assemblyidentity >< bindingredirect oldversion = "1.0.0.0-3.0.0.0" newversion = "3.0.0.0" ></ bindingredirect ></ dependentassembly >< dependentassembly >< assemblyidentity name = "System.Web.Mvc" publickeytoken = "31bf3856ad364e35" ></ assemblyidentity >< bindingredirect oldversion = "1.0.0.0-5.0.0.0" newversion = "5.0.0.0" ></ bindingredirect ></ dependentassembly >< dependentassembly >< assemblyidentity name = "System.Web.Optimization" publickeytoken = "31bf3856ad364e35" ></ assemblyidentity >< bindingredirect oldversion = "1.0.0.0-1.1.0.0" newversion = "1.1.0.0" ></ bindingredirect ></ dependentassembly >< dependentassembly >< assemblyidentity name = "System.Web.WebPages" publickeytoken = "31bf3856ad364e35" ></ assemblyidentity >< bindingredirect oldversion = "1.0.0.0-3.0.0.0" newversion = "3.0.0.0" ></ bindingredirect ></ dependentassembly >< dependentassembly >< assemblyidentity name = "WebGrease" publickeytoken = "31bf3856ad364e35" ></ assemblyidentity >< bindingredirect oldversion = "0.0.0.0-1.5.2.14234" newversion = "1.5.2.14234" ></ bindingredirect ></ dependentassembly ></ assemblybinding ></ runtime >< entityframework >< defaultconnectionfactory type = "System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" ></ defaultconnectionfactory >< providers >< provider invariantname = "System.Data.SqlClient" type = "System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" ></ provider ></ providers ></ entityframework ></ configuration > |
以上,
- 增加了connectionStrings节点,将自动创建localdb数据库
- 在appSettings节点中增加了一个key为owin:AppStartup项,这是确保OWIN运行正常的全局配置
在Models文件夹下创建如下类。
1 2 3 | public class AppUser : IdentityUser { } |
在解决方案下创建Infrastructure文件夹。
在Infrastructure文件夹下创建一个上下文类,需要实现IdentityDbContext接口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | public class AppIdentityDbContext : IdentityDbContext<appuser> { public AppIdentityDbContext() : base ( "IdentityDb" ) { } static AppIdentityDbContext() { //使用EF Code First第一次创建的时候调用 Database.SetInitializer<appidentitydbcontext>( new IdentityDbInit()); } public static AppIdentityDbContext Create() { return new AppIdentityDbContext(); } } //初始化 public class IdentityDbInit : DropCreateDatabaseIfModelChanges<appidentitydbcontext> { protected override void Seed(AppIdentityDbContext context) { PerformInitialSetup(context); base .Seed(context); } //初始化工作 public void PerformInitialSetup(AppIdentityDbContext context) { } }</appidentitydbcontext></appidentitydbcontext></appuser> |
在Infrastructure文件夹下创建一个管理用户的类,需要继承UserManager
还记得,先前在appSettings节点中配置了一个如下方式:
OWIN需要一个全局启动文件,默认会到项目的顶级命名空间下找IdentityConfig这个类。
那就在App_Start中创建IdentityConfig这个类,这个类在WebApplication4这个命名空间下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | namespace WebApplication4 { public class IdentityConfig { public void Configuration(IAppBuilder app) { app.CreatePerOwinContext<appidentitydbcontext>(AppIdentityDbContext.Create); app.CreatePerOwinContext<appusermanager>(AppUserManager.Create); app.UseCookieAuthentication( new CookieAuthenticationOptions { AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, LoginPath = new Microsoft.Owin.PathString( "/Account/Login" ) }); } } }</appusermanager></appidentitydbcontext> |
显示用户
创建AdminController,现在可以向视图传递所有的用户了,编写如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public class AdminController : Controller { public ActionResult Index() { return View(UserManager.Users); } private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<appusermanager>(); } } }</appusermanager> |
再创建Admin/Index.cshtml类型为IEnumerable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @model IEnumerable< webapplication4.models.appuser > @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } < div class = "panel panel-primary" > < div class = "panel-heading" > 所有用户账户 </ div > @if (Model.Count() == 0) { } else { foreach (WebApplication4.Models.AppUser user in Model) { } } < table class = "table table-striped" > < tbody >< tr > < th >ID</ th > < th >Name</ th > < th >Email</ th > < th ></ th > </ tr >< tr >< td colspan = "4" class = "text-center" >还没有创建用户</ td ></ tr >< tr > < td >@user.Id</ td > < td >@user.UserName</ td > < td >@user.Email</ td > < td > @using (Html.BeginForm("Delete", "Admin", new { id = user.Id })) { @Html.ActionLink("编辑", "Edit", new { id = user.Id }, new { @class = "btn btn-primary btn-xs" }) < button class = "btn btn-danger btn-xs" type = "submit" > 删除 </ button > } </ td > </ tr ></ tbody ></ table > </ div > @Html.ActionLink("创建用户", "Create", null, new { @class = "btn btn-primary" })</ webapplication4.models.appuser > |
创建用户
在Models文件夹下创建一个视图模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 | namespace WebApplication4.Models { public class CreateModel { public string Id { get ; set ; } [Required] public string Name { get ; set ; } [Required] public string Email { get ; set ; } [Required] public string Password { get ; set ; } } } |
在AdminController中添加创建用户相关的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | public class AdminController : Controller { public ActionResult Index() { return View(UserManager.Users); } //创建显示 public ActionResult Create() { return View(); } [HttpPost] public async Task<actionresult> Create(CreateModel model) { if (ModelState.IsValid) { var user = new AppUser{UserName = model.Name, Email = model.Email}; IdentityResult result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { return RedirectToAction( "Index" ); } else { AddErrorsFromResult(result); } } return View(model); } //创建接收 private void AddErrorsFromResult(IdentityResult result) { foreach ( var error in result.Errors) { ModelState.AddModelError( "" , error); } } private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<appusermanager>(); } } }</appusermanager></actionresult> |
在Admin/Create.cshtml视图页中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @model WebApplication4.Models.CreateModel @{ ViewBag.Title = "Create"; Layout = "~/Views/Shared/_Layout.cshtml"; } < h2 >Create</ h2 > @using (Html.BeginForm()) { @Html.AntiForgeryToken() < div class = "form-horizontal" > < h4 >创建用户</ h4 > < hr > @Html.ValidationSummary(true) < div class = "form-group" > @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.Password) @Html.ValidationMessageFor(model => model.Password) </ div > </ div > < div class = "form-group" > < div class = "col-md-offset-2 col-md-10" > < input type = "submit" value = "创建用户" class = "btn btn-default" > </ div > </ div > </ div > } < div > @Html.ActionLink("返回", "Index") </ div > |
点击”创建”按钮,创建成功返回显示用户页面。
oh, my god,只是配置了一下就有数据了? 数据在哪呢?
点击左上角的”服务器资源管理器”,右键”IdentityDb”,点击”刷新”。
再打开AspNetUsers表,刚创建的用户赫然在列。
好像还有点欠缺,用户输入密码的时候,总应该有些限制吧。
能想到的,ASP.NET Identity都为我们准备好了。有一个PasswordValidator类就是干这个的。
在Infrastructure文件夹中创建一个PasswordValidator类的继承子类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | namespace WebApplication4.Infrastructure { public class CustomPasswordValidator : PasswordValidator { public override async Task<identityresult> ValidateAsync( string pass) { IdentityResult result = await base .ValidateAsync(pass); if (pass.Contains( "12345" )) { var errors = result.Errors.ToList(); errors.Add( "密码中包含太多连续数字" ); result = new IdentityResult(errors); } return result; } } }</identityresult> |
然后需要把这个规则告诉UserManager。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | namespace WebApplication4.Infrastructure { public class AppUserManager : UserManager<appuser> { public AppUserManager(IUserStore<appuser> store) : base (store) { } public static AppUserManager Create(IdentityFactoryOptions<appusermanager> options, IOwinContext context) { //identity ef上下文 AppIdentityDbContext db = context.Get<appidentitydbcontext>(); //与identity ef相关的UserStore IUserStore<appuser> us = new UserStore<appuser>(db); AppUserManager manager = new AppUserManager(us); //密码相关 manager.PasswordValidator = new CustomPasswordValidator { RequiredLength = 6, RequireNonLetterOrDigit = false , RequireDigit = false , RequireLowercase = true , RequireUppercase = true }; return manager; } } }</appuser></appuser></appidentitydbcontext></appusermanager></appuser></appuser> |
再次运行程序,创建用户页面,尝试输入不通过的密码。
不过,关于密码的规则,似乎可以在View Model的验证层面就可以解决掉。
编辑和删除用户
在AdminController中增加编辑和删除的部分。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | public class AdminController : Controller { public ActionResult Index() { return View(UserManager.Users); } //创建显示 public ActionResult Create() { return View(); } //创建接收 [HttpPost] public async Task<actionresult> Create(CreateModel model) { if (ModelState.IsValid) { var user = new AppUser{UserName = model.Name, Email = model.Email}; IdentityResult result = await UserManager.CreateAsync(user, model.Password); if (result.Succeeded) { return RedirectToAction( "Index" ); } else { AddErrorsFromResult(result); } } return View(model); } //编辑显示 public async Task<actionresult> Edit( string id) { AppUser user = await UserManager.FindByIdAsync(id); if (User != null ) { CreateModel createModel = new CreateModel(); createModel.Id = user.Id; createModel.Email = user.Email; createModel.Name = user.UserName; createModel.Password = user.PasswordHash; return View(createModel); } else { return RedirectToAction( "Index" ); } } //接收编辑 [HttpPost] public async Task<actionresult> Edit(CreateModel createModel) { if (ModelState.IsValid) { AppUser user = await UserManager.FindByIdAsync(createModel.Id); if (user != null ) { //关于邮箱 user.Email = createModel.Email; IdentityResult validEmail = await UserManager.UserValidator.ValidateAsync(user); if (!validEmail.Succeeded) { AddErrorsFromResult(validEmail); } user.UserName = createModel.Name; //关于密码 IdentityResult validPass = null ; if (createModel.Password != string .Empty) { validPass = await UserManager.PasswordValidator.ValidateAsync(createModel.Password); if (validPass.Succeeded) { user.PasswordHash = UserManager.PasswordHasher.HashPassword(createModel.Password); } else { AddErrorsFromResult(validPass); } } user.Email = createModel.Email; //验证结果 if ((validEmail.Succeeded && validPass == null ) || (validEmail.Succeeded && createModel.Password != string .Empty && validPass.Succeeded)) { IdentityResult result = await UserManager.UpdateAsync(user); if (result.Succeeded) { return RedirectToAction( "Index" ); } else { AddErrorsFromResult(result); } } else { ModelState.AddModelError( "" , "无此用户" ); } } return View(createModel); } else { return View(createModel); } } //删除 [HttpPost] public async Task<actionresult> Delete( string id) { AppUser user = await UserManager.FindByIdAsync(id); if (user != null ) { IdentityResult result = await UserManager.DeleteAsync(user); if (result.Succeeded) { return RedirectToAction( "Index" ); } else { return View( "Error" , result.Errors); } } else { return View( "Error" , new string [] { "没有此用户" }); } } private void AddErrorsFromResult(IdentityResult result) { foreach ( var error in result.Errors) { ModelState.AddModelError( "" , error); } } private AppUserManager UserManager { get { return HttpContext.GetOwinContext().GetUserManager<appusermanager>(); } } }</appusermanager></actionresult></actionresult></actionresult></actionresult> |
Admin/Edit.cshtml视图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @model WebApplication4.Models.CreateModel @{ ViewBag.Title = "Edit"; Layout = "~/Views/Shared/_Layout.cshtml"; } < h2 >Edit</ h2 > @using (Html.BeginForm()) { @Html.AntiForgeryToken() < div class = "form-horizontal" > < hr > @Html.ValidationSummary(true) @Html.HiddenFor(model => model.Id) < div class = "form-group" > @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) </ div > </ div > < div class = "form-group" > @Html.LabelFor(model => model.Password, new { @class = "control-label col-md-2" }) < div class = "col-md-10" > @Html.EditorFor(model => model.Password) @Html.ValidationMessageFor(model => model.Password) </ div > </ div > < div class = "form-group" > < div class = "col-md-offset-2 col-md-10" > < input type = "submit" value = "保存" class = "btn btn-default" > </ div > </ div > </ div > } < div > @Html.ActionLink("返回", "Index") </ div > |
另外,如果删除失败,跳转到Shared/Error.cshtml视图页。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @model IEnumerable< string > @{ ViewBag.Title = "Error";} < div class = "alert alert-danger" > @switch (Model.Count()) { case 0: @: Something went wrong. Please try again break; case 1: @Model.First(); break; default: @: 发现如下错误: < ul > @foreach (string error in Model) { < li >@error</ li > } </ ul > break; } </ div > @Html.ActionLink("确定", "Index", null, new { @class = "btn btn-default" })</ string > |
至此,使用ASP.NET Identy实现对用户的增删改查完毕,ASP.NET Identity真的很好很强大!
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对IT俱乐部的支持。如果你想了解更多相关内容请查看下面相关链接