ASP.NET?MVC使用Identity增刪改查用戶
源碼在這里:https://github.com/darrenji/UseIdentityCRUDUserInMVC,本地下載
在VS2013中創(chuàng)建一個MVC項目,用默認的"無身份驗證"作為身份驗證機制。
通過控制臺下載Bootstrap。
Install-Package -version 3.0.3 bootstrap
下載成功后,在解決方案下的Content和Scripts多了該版本的css和js文件。
把創(chuàng)建項目默認HomeController中的所有Action以及/Views/Home下的所有視圖刪除。
熱熱身
先來做一個簡單練習。
在HomeController中的Index方法中,把一個字典傳遞給視圖。
public class HomeController : Controller
{
public ActionResult Index()
{
Dictionary<string, object> data = new Dictionary<string, object>();
data.Add("placeholder", "placeholder");
return View(data);
}
}_Layout.cshtml設置如下:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ASP.NET Identity實戰(zhàn)</title>
<link href="~/Content/bootstrap.min.css" rel="external nofollow" rel="stylesheet" />
<link href="~/Content/bootstrap-theme.min.css" rel="external nofollow" rel="stylesheet" />
<style>
.container {padding-top:10px;}
.validation-summary-errors{color:red;}
</style>
</head>
<body>
<div class="container">
@RenderBody()
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>Home/Index.cshtml視圖中:
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="panel panel-primary">
<div class="panel-heading">用戶明細</div>
<table class="table table-striped">
@foreach (string key in Model.Keys)
{
<tr>
<th>@key</th>
<td>@Model[key]</td>
</tr>
}
</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如下:
<?xml version="1.0" encoding="utf-8"?>
<!--
有關如何配置 ASP.NET 應用程序的詳細信息,請訪問
http://go.microsoft.com/fwlink/?LinkId=301880
-->
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</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"/>
</connectionStrings>
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="owin:AppStartup" value="WebApplication4.IdentityConfig" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>以上,
- 增加了connectionStrings節(jié)點,將自動創(chuàng)建localdb數(shù)據(jù)庫
- 在appSettings節(jié)點中增加了一個key為owin:AppStartup項,這是確保OWIN運行正常的全局配置
在Models文件夾下創(chuàng)建如下類。
public class AppUser : IdentityUser
{
}在解決方案下創(chuàng)建Infrastructure文件夾。
在Infrastructure文件夾下創(chuàng)建一個上下文類,需要實現(xiàn)IdentityDbContext<>接口。
public class AppIdentityDbContext : IdentityDbContext<AppUser>
{
public AppIdentityDbContext()
: base("IdentityDb")
{
}
static AppIdentityDbContext()
{
//使用EF Code First第一次創(chuàng)建的時候調(diào)用
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)
{ }
}在Infrastructure文件夾下創(chuàng)建一個管理用戶的類,需要繼承UserManager<AppUser>類。
還記得,先前在appSettings節(jié)點中配置了一個如下方式:
<add key="owin:AppStartup" value="WebApplication4.IdentityConfig" />
OWIN需要一個全局啟動文件,默認會到項目的頂級命名空間下找IdentityConfig這個類。
那就在App_Start中創(chuàng)建IdentityConfig這個類,這個類在WebApplication4這個命名空間下。
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")
});
}
}
}顯示用戶
創(chuàng)建AdminController,現(xiàn)在可以向視圖傳遞所有的用戶了,編寫如下:
public class AdminController : Controller
{
public ActionResult Index()
{
return View(UserManager.Users);
}
private AppUserManager UserManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
}再創(chuàng)建Admin/Index.cshtml類型為IEnumerable<AppUser>的強類型視圖。
@model IEnumerable<WebApplication4.Models.AppUser>
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="panel panel-primary">
<div class="panel-heading">
所有用戶賬戶
</div>
<table class="table table-striped">
<tr><th>ID</th><th>Name</th><th>Email</th><th></th></tr>
@if (Model.Count() == 0)
{
<tr><td colspan="4" class="text-center">還沒有創(chuàng)建用戶</td></tr>
}
else
{
foreach (WebApplication4.Models.AppUser user in Model)
{
<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>
}
}
</table>
</div>
@Html.ActionLink("創(chuàng)建用戶", "Create", null, new { @class = "btn btn-primary" })
創(chuàng)建用戶
在Models文件夾下創(chuàng)建一個視圖模型。
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中添加創(chuàng)建用戶相關的方法。
public class AdminController : Controller
{
public ActionResult Index()
{
return View(UserManager.Users);
}
//創(chuàng)建顯示
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);
}
//創(chuàng)建接收
private void AddErrorsFromResult(IdentityResult result)
{
foreach(var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
private AppUserManager UserManager
{
get
{
return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();
}
}
}在Admin/Create.cshtml視圖頁中:
@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>創(chuàng)建用戶</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="創(chuàng)建用戶" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("返回", "Index")
</div>
點擊"創(chuàng)建"按鈕,創(chuàng)建成功返回顯示用戶頁面。

oh, my god,只是配置了一下就有數(shù)據(jù)了? 數(shù)據(jù)在哪呢?
點擊左上角的"服務器資源管理器",右鍵"IdentityDb",點擊"刷新"。

再打開AspNetUsers表,剛創(chuàng)建的用戶赫然在列。

好像還有點欠缺,用戶輸入密碼的時候,總應該有些限制吧。
能想到的,ASP.NET Identity都為我們準備好了。有一個PasswordValidator類就是干這個的。
在Infrastructure文件夾中創(chuàng)建一個PasswordValidator類的繼承子類。
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("密碼中包含太多連續(xù)數(shù)字");
result = new IdentityResult(errors);
}
return result;
}
}
}然后需要把這個規(guī)則告訴UserManager。
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;
}
}
}再次運行程序,創(chuàng)建用戶頁面,嘗試輸入不通過的密碼。

不過,關于密碼的規(guī)則,似乎可以在View Model的驗證層面就可以解決掉。
編輯和刪除用戶
在AdminController中增加編輯和刪除的部分。
public class AdminController : Controller
{
public ActionResult Index()
{
return View(UserManager.Users);
}
//創(chuàng)建顯示
public ActionResult Create()
{
return View();
}
//創(chuàng)建接收
[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>();
}
}
}Admin/Edit.cshtml視圖。
@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>另外,如果刪除失敗,跳轉(zhuǎn)到Shared/Error.cshtml視圖頁。
@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:
@: 發(fā)現(xiàn)如下錯誤:
<ul>
@foreach (string error in Model)
{
<li>@error</li>
}
</ul>
break;
}
</div>
@Html.ActionLink("確定", "Index", null, new { @class = "btn btn-default" })至此,使用ASP.NET Identy實現(xiàn)對用戶的增刪改查完畢,ASP.NET Identity真的很好很強大!
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對腳本之家的支持。如果你想了解更多相關內(nèi)容請查看下面相關鏈接
相關文章
通過RadioButton對DataList控件進行單選實例說明
本例實現(xiàn)通過RadioButton對DataList控件進行單選,aspx拉一個DataList控件,把RadioButton置于DataList的ItemTemplate模版內(nèi);在.aspx.cs內(nèi)為DataList控件綁定數(shù)據(jù),很實用的功能,感興趣的朋友可以了解下啊2013-01-01
asp.net中3種驗證碼示例(實現(xiàn)代碼)(數(shù)字,數(shù)字字母混和,漢字)
asp.net中3種驗證碼示例代碼,分別是數(shù)字,數(shù)字字母混和,漢字,需要的朋友可以參考下2012-10-10
ASP.NET MVC中HtmlHelper控件7個大類中各個控件使用詳解
本文主要介紹HtmlHelper類控件的使用方法,給初涉MVC的朋友一些幫助,有需要的朋友可以參考一下。2016-03-03
.NET異步編程總結----四種實現(xiàn)模式代碼總結
本篇文章主要介紹了.NET異步編程總結----四種實現(xiàn)模式,詳細的介紹了每種方法的實現(xiàn)和實例,具有一定的參考價值,有興趣的可以了解一下。2016-12-12
asp.net中通過DropDownList的值去控制TextBox是否可編寫的實現(xiàn)代碼
Web窗體上有兩控件,DropDownList1,TextBox1,當DropDownList的值選擇是YES的時候,TextBox1可編輯,當選擇NO的時候,TextBox1的值為空,并且不能編輯,該如何實現(xiàn)2012-11-11
ASP.NET Core文件壓縮常見使用誤區(qū)(最佳實踐)
本文給大家分享ASP.NET Core文件壓縮常見的三種誤區(qū),就每種誤區(qū)給大家講解的非常詳細,是項目實踐的最佳紀錄,對ASP.NET Core文件壓縮相關知識感興趣的朋友一起看看吧2021-05-05
Asp.Net Core中服務的生命周期選項區(qū)別與用法詳解
這篇文章主要給大家介紹了關于Asp.Net Core中服務的生命周期選項區(qū)別與用法的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-11-11

