ASP.NET Identity教程二:(用户管理)
由于我们这里使用的是 ASP.NET Identity 来管理用户,所以 User 数据实体是继承了 IdentityUser 的,我们只需要在派生类中编写需要扩展的属性即可。而在表现层,也就是 Web 应用程序这一层,我们只需要编写 ViewModel 即可,ViewModel 只在视图和控制中使用。最终在提交到服务器时,还是需要转换为数据实体 Model 的。
在“Yidosoft.Identity”项目中添加一个名称为“ViewModels”的文件夹,将所有的ViewModel 都放在该文件夹中。

1. 注册用户
注册用户是指将用户的信息添加到数据库中,是有用户在网站上自行完成的
1.1. 编写 AddUserViewModel
在“ViewModels”文件夹中添加一个名称为“AddUserViewModel”的类,然后编写如
下代码:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace jsdhh2.ViewModels
{
public class AddUserViewModel
{
#region 扩展
[Display(Name = "用户名")]
public string UserName { get; set; }
[Display(Name = "电话(手机/固话)")]
[Phone]
public string PhoneNumber { get; set; }
#endregion
[Required]
[EmailAddress]
[Display(Name = "电子邮件")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "{0} 必须至少包含 {2} 个字符。", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "密码")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "确认密码")]
[Compare("Password", ErrorMessage = "密码和确认密码不匹配。")]
public string ConfirmPassword { get; set; }
}
在 ViewModel 中,可以使用数据验证和注解来保证数据的正确性。
1.2. 编写 Add 方法
在 UserController 控制器中添加一个带有 HttpGet 特性的 Add()方法,用于呈现添加用户的表单信息视图。再添加一个带有 HttpPost 特性的 Add()方法,用于提交
用户信息到数据库中。完整的代码如下:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Add(AddUserViewModel addUserModel)
{
if (ModelState.IsValid)
{
var _creatTime = DateTime.Now; //注册时间
var _headerPic = "/Content/noheaderpic.png"; //默认的显示一个头像
var user = new User { UserName = addUserModel.UserName, Email = addUserModel.Email, PhoneNumber = addUserModel.PhoneNumber, CreateTime =_creatTime, HeaderPic = _headerPic };
var result = await UserManager.CreateAsync(user, addUserModel.Password);
if (result.Succeeded)
{
//登录
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// 发送包含此链接的电子邮件
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "User", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "确认你的帐户", "请通过单击 <a href=\"" + callbackUrl + "\">这里</a>来确认你的帐户");
//return RedirectToAction("List", "User");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(addUserModel);
}
在这里的两个 Add()方法上都添加了 AllowAnonymous 特性,表示可以被匿名访问。ValidateAntiForgeryToken 特性用于阻止 CSRF 攻击。
在这里我们使用了 CreateAsync()异步方法来向数据库添加用户信息,在UserManager 中,定义了许多的异步操作的方法,异步方法都是以 Async 结尾的。
.3. 编写 Add 视图
在”项目的“Views”“User”中添加一个名称为“Add”的视图,如图
中修改视图名称为“Add”,点击“添加”按钮。如图

第一次为空的 MVC 项目添加视图时,VS2015 会自动添加一些其它的文件。如:bootstrap.css、Site.css、Jquery 文件及一些公共视图,还有就是“_Layout.cshtml”
视图的基本样式。
这里使用 Bootstrap 为 Add.cshtml 视图布局页面。在 add.cshtml 视图中编写如下代码:
@model jsdhh2.ViewModels.AddUserViewModel
@{
ViewBag.Title = "Add";
}
@using (Html.BeginForm("Add", "User", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>添加用户。</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.PhoneNumber, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.PhoneNumber, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Email, 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="保存" />
</div>
</div>
}
在此视图中使用了Bootstrap的class来布局表单样式。并使用ValidationSummary()方法来执行验证。
4. 测试运行结果
add.cshtml 视图编写完成之后,就可以在 Visual Studio 2015 中按下 F5 键来运行一下。打开 add.cshtml 视图,如图 7-5 所示:中可以按 F5,也可以点击调试按钮。如图 7-6 所示:

此时的图 7-6 使用的是带 HttpGet 特性的 Add()方法返回的视图页面。
现在点击一下图 7-6 的“保存”按钮,浏览器不会刷新,会执行客户端验证。如图

凡是在 ViewModel 里使用了[Required]特性,都会在没有输入任何值的情况下出
现 7-7 的非空验证。
在点击“保存”按钮时,注意浏览器的刷新情况,如果没有刷新,则就执行了客户
端验证,如果刷新了,则会执行服务器端验证。
现在在图 7-7 的表单中输入内容。如图 7-8 所示:

输入完成后,点击“保存”按钮。注意:由于这是第一次使用 Entity Framework 提交数据到数据库,所以会检查相关的数据库、表是否已经创建,如果未创建,则
就会立即创建并执行操作。
当点击“保存”按钮后,就会执行带 HttpPost 特性的 Add()方法中的代码。图 7-8 的表单数据保存成功后会转到首页(Home/Index),这也是默认路由指定的
默认路径。如图 7-9 所示:

但是也表明了我们的执行操作成功了。打开数据库查看一下,如图 7-10 所示:

在图 7-10 中可以看到,“YDIdentityDb”数据库已经创建成功了,并且还为 ASP.NETIdentity 创建相应的表结构。
与用户相关的信息是存在“AspNetUsers”表中的,打开该表可以看到我们新添加的用户信息。这也证明我们在上面所做的操作已经执行成功了。
从这些操作中可以看到,我们使用了 Entity Framework 操作持久化数据非常方便,不仅不需要编写 SQL 语句,就连数据库和表结构都不需要我们创建。另外在ASP.NET Identity 中,对用户属性的扩展是那么的方便,这在 ASP.NET Membership中,这么扩展用户属性是做不到的。
2. 用户列表
管理用户都是从用户列表开始的,在用户列表中可以查看用户信息、编辑用户信息和删除用户信息。当然也可以放个添加用户的链接用于新增用户。用户列表就
是管理用户的入口。
在用户列表视图中,我们不使用 ViewModel,直接使用 User 类即可,因为UserManager 提供了获取所有用户的方法,直接调用即可。
.2.1. 编写 List 方法
在 UserController 控制器中添加一个带有 HttpGet 特性的 List()方法,用于以列表的形式显示所有的用户。完整的代码如下:
[HttpGet]
public ActionResult List()
{
var users = UserManager.Users.ToList();
return View(users);
}
2.2. 编写 List 视图
项目的“Views”“User”文件夹中添加一个名称为“List”的视图。
@model IEnumerable<jsdhh2.Models.User>
@{
ViewBag.Title = "List";
}
<div class="wrapper wrapper-content">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h2>用户管理</h2>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="form-group">
<a class="btn btn-primary" href="/User/Add">添加</a>
<button id="btnEdit" type="button" class="btn btn-info " onclick="editModel()"><i class="fa fa-pencil"></i> 编辑</button>
<button id="btnDel" type="button" class="btn btn-danger " onclick="delData()">
<i class="fa fa-remove"></i> <span class="bold">删除</span>
</button>
<button id="btnSetRole" type="button" class="btn btn-info "><i class="fa fa-user"></i> 角色授权</button>
<button id="btnResetPwd" class="btn btn-warning"><i class="fa fa-undo"></i> 重置密码</button>
</div>
<div class="form-group">
<div class="input-group">
<input id="txtSearchKey" type="text" class="input form-control" placeholder="搜索关键字" />
<span class="input-group-btn">
<button id="btnSearch" class="btn btn btn-primary" type="button"> <i class="fa fa-search"></i> 搜索</button>
</span>
</div>
</div>
<div class="jqGrid_wrapper">
<table id="table_list"></table>
<div id="pager_list"></div>
</div>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th>用户名</th>
<th>电子邮件</th>
<th>QQ号码</th>
<th>微信号码</th>
</tr>
</thead>
<tbody>
@foreach (var user in Model)
{
<tr>
<td>@Html.DisplayFor(m => user.UserName)</td>
<td>@Html.DisplayFor(m => user.Email)</td>
<td>@Html.DisplayFor(m => user.QQ)</td>
<td>@Html.DisplayFor(m => user.PhoneNumber)</td>
<td>@Html.DisplayFor(m => user.CreateTime) </td>
<td>
@Html.ActionLink("编辑", "Edit", new { id = user.Id },new { @class= "btn btn-info" })
@Html.ActionLink("删除", "Del", new { id = user.Id }, new { @class = "btn btn-danger" })
</td>
</tr>
}
</tbody>
</table>
显示效果为

这里使用了表格 table 以列表的形式的显示用户基本信息,使用了 Bootstrap 中的class=”table”来布局样式。在<table>标记上面还添加了一个链接,用于转到添加用户的页面:
<a class="btn btn-primary" href="/User/Add">添加</a>
这样可以在用户列表中直接点击“添加用户”链接转到添加用户的页面。那么此时,我们就可以在“Add()”方法中,将添加用户成功后转到的页面修改为 List 页面。打开“UserController”,修改带有 HttpPost 的 Add()方法。如下代码:
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Add(AddUserViewModel addUserModel)
{
if (ModelState.IsValid)
{
var user = new User { UserName = addUserModel.Email, Email = addUserModel.Email, QQNumber = addUserModel.QQNumber, WechatNumber = addUserModel.WechatNumber };
var result = await UserManager.CreateAsync(user, addUserModel.Password);
if (result.Succeeded)
{
//登录
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// 发送包含此链接的电子邮件
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "User", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "确认你的帐户", "请通过单击 <a href=\"" + callbackUrl + "\">这里</a>来确认你的帐户");
return RedirectToAction("List", "User");
//eturn RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(addUserModel);
现在新建一个用户,自动就跑到所有用户列表了。
3.增加详细页面显示
先在List视图中增加详细信息按钮
<td>
@Html.ActionLink("详情", "DetailsList", new { id = user.Id }, new { @class = "btn btn-info" })
@Html.ActionLink("编辑", "Edit", new { id = user.Id },new { @class= "btn btn-info" })
@Html.ActionLink("删除", "Del", new { id = user.Id }, new { @class = "btn btn-danger" })
</td>
在UserControoer中增加DetailsList方法
[HttpGet]
public ActionResult DetailsList(string id)
{
if (string.IsNullOrWhiteSpace(id))
{
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
}
User user = UserManager.FindById(id);
return View(user);
}
然后增加一个DetailsList视图
@model jsdhh2.Models.User
@{
ViewBag.Title = "List";
}
<div class="wrapper wrapper-content">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h2>详细信息</h2>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="form-group">
<a class="btn btn-primary" href="/User/List">返回</a>
</div>
</div>
</div>
</div>
<div>
<hr />
<dl class="dl-horizontal">
<dt>
</dt>
<dd>
<img src="@Model.HeaderPic" width="80" height="80" />
</dd>
<dt>
@Html.DisplayNameFor(model => model.UserName)
</dt><dd>
@Html.DisplayFor(model => model.UserName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.RealName)
</dt><dd>
@Html.DisplayFor(model => model.RealName)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Email)
</dt><dd>
@Html.DisplayFor(model => model.Email)
</dd>
<dt>
@Html.DisplayNameFor(model => model.QQ)
</dt><dd>
@Html.DisplayFor(model => model.QQ)
</dd>
<dt>
@Html.DisplayNameFor(model => model.PhoneNumber)
</dt><dd>
@Html.DisplayFor(model => model.PhoneNumber)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Address)
</dt><dd>
@Html.DisplayFor(model => model.Address)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Gender)
</dt><dd>
@Html.DisplayFor(model => model.Gender)
</dd>
<dt>
@Html.DisplayNameFor(model => model.SpouseId)
</dt><dd>
@Html.DisplayFor(model => model.SpouseId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.Address)
</dt><dd>
@Html.DisplayFor(model => model.Address)
</dd>
<dt>
@Html.DisplayNameFor(model => model.DepartmentId)
</dt><dd>
@Html.DisplayFor(model => model.DepartmentId)
</dd>
<dt>
@Html.DisplayNameFor(model => model.BirthDate)
</dt><dd>
@Html.DisplayFor(model => model.BirthDate)
</dd>
<dt>
@Html.DisplayNameFor(model => model.TheHour)
</dt><dd>
@Html.DisplayFor(model => model.TheHour)
</dd>
<dt>
@Html.DisplayNameFor(model => model.DetailedTime)
</dt>
<dd>
@Html.DisplayFor(model => model.DetailedTime)
</dd>
</div>
显示效果为

4.
浙公网安备 33010602011771号