ASP.NET MVC 5 安全性和创建用户角色

本文将介绍如何在 ASP.NET MVC 5 应用程序 中使用 ASP.NET Identity 创建和使用角色、扩展用户属性及相关知识。

主要内容包括:

  • 创建管理员角色和超级用户
  • 用户注册时选择角色
  • 使用用户名进行登录
  • 角色管理
  • 扩展用户属性
  • 针对Controller或Action的授权

准备工作

在 Visual Studio 2017 中 创建 ASP.NET Web 应用程序(.NET Framework),我们将应用程序命名为“UserRoleDemo”,在创建应用程序时更改身份验证方式为“个人用户账户”,其他均为默认设置。

创建管理员角色和超级用户

修改 Startup.cs 文件,在 Configuration 方法中调用自定义的CreateRolesandUsers() 方法来创建默认角色和管理员用户。

在CreateRolesandUsers() 方法中将检查管理员角色(命名为“Admin”)是否已被创建,如果名称为“Admin”的角色没有创建,则创建一个名称为“Admin”的新角色和一个超级用户(命名为“sa”),并将该用户的角色设置为“Admin”。

Startup.cs

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin;
using Owin;
using UserRoleDemo.Models;

[assembly: OwinStartup(typeof(UserRoleDemo.Startup))]
namespace UserRoleDemo
{
    public partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
            CreateRolesAndUsers();
        }


        // 创建管理员角色和超级用户    
        private void CreateRolesAndUsers()
        {
            ApplicationDbContext context = new ApplicationDbContext();

            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
            var userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));

            // 判断管理员角色是否存在     
            if (!roleManager.RoleExists("Admin"))
            {
                // 创建角色 - Admin
                var role = new IdentityRole
                {
                    Name = "Admin"
                };
                roleManager.Create(role);

                // 创建超级用户 - sa
                var user = new ApplicationUser
                {
                    UserName = "sa",
                    Email = "sa@mercator.asia"
                };

                string userPWD = "Mercator.asia";

                var chkUser = userManager.Create(user, userPWD);

                // 指定超级用户的角色    
                if (chkUser.Succeeded)
                {
                    var result1 = userManager.AddToRole(user.Id, "Admin");
                }
            }

            // 创建角色 - Manager
            if (!roleManager.RoleExists("Manager"))
            {
                var role = new IdentityRole
                {
                    Name = "Manager"
                };
                roleManager.Create(role);
            }

            // 创建角色 - Employee
            if (!roleManager.RoleExists("Employee"))
            {
                var role = new IdentityRole
                {
                    Name = "Employee"
                };
                roleManager.Create(role);
            }
        }
    }
}

用户注册时选择角色

通过 ASP.NET Web 应用程序(.NET Framework) 模板创建的应用程序在用户注册时默认只能输入邮箱和密码,下面我们将实现在用户注册时选择角色。

模板程序默认是以邮箱作为用户名,在实现选择角色功能时我们也会增加输入独立的用户名的功能。

视图部分

修改Register.cshtml文件,在其中添加用户名行和角色行。

Views/Account/Register.cshtml

@model UserRoleDemo.Models.RegisterViewModel
@{
    ViewBag.Title = "注册";
}

<h2>@ViewBag.Title。</h2>

@using (Html.BeginForm("Register", "Account", 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.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">
        @Html.Label("user Role", new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.DropDownList("UserRoles", (SelectList)ViewBag.Name, " ")
        </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>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

模型部分

修改 Models/AccountViewModel.cs 文件,在 RegisterViewModel 中添加 UserRoles 和 UserName 等两个属性。

Models/AccountViewModel.cs(局部)

    public class RegisterViewModel
    {
        [Required]
        [Display(Name = "所属角色")]
        public string UserRoles { get; set; }

        [Required]
        [Display(Name = "用户名")]
        public string UserName { get; set; }

        [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; }
    }

控制器部分

修改 Controllers/AccountController.cs 文件,把除“Admin”外的所有角色名称显示在下拉框中,并在注册按钮的点击事件中实现写入用户名和角色属性的功能。

首先创建一个 ApplicationDBContext 对象。(ApplicationDBContext 是一个用于实现ASP.NET Identity 数据库读写功能的类,例如创建用户、角色等)

为AccountController类添加一个私有成员:

Controllers/AccountController.cs(局部)

        private readonly ApplicationDbContext context;

修改AccountController的构造函数以初始化context对象:

Controllers/AccountController.cs(局部)

        public AccountController()
        {
            context = new ApplicationDbContext();
        }

通过 ApplicationDBContext 对象我们可以获取数据库中的所有角色。用户注册时我们不允许选择“Admin”角色,因此,在Register ActionResult 中查询所有非“Admin”角色用于在视图的角色下拉框中显示。

Controllers/AccountController.cs(局部)

        //
        // GET: /Account/Register
        [AllowAnonymous]
        public ActionResult Register()
        {
            ViewBag.Name = new SelectList(context.Roles.Where(u => !u.Name.Contains("Admin"))
                                    .ToList(), "Name", "Name");
            return View();
        }

在AspNetUsers数据表中默认是将Email作为用户名来存储的,这里我们改为直接存储用户输入的用户名。

用户创建成功后,通过调用 UserManager.AddToRoleAsync 方法为用户设置其选择的角色。

Controllers/AccountController.cs(局部)

        //
        // POST: /Account/Register
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                // 将UserName = model.Email替换为UserName = model.UserName
                var user = new ApplicationUser { UserName = model.UserName, Email = model.Email };
                var result = await UserManager.CreateAsync(user, model.Password);
                if (result.Succeeded)
                {
                    await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);

                    // 有关如何启用帐户确认和密码重置的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=320771
                    // 发送包含此链接的电子邮件
                    // 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, "确认你的帐户", "请通过单击 <a href="" + callbackUrl + "">這裏</a>来确认你的帐户");

                    // 设置创建的新用户添加到其选择的角色
                    await UserManager.AddToRoleAsync(user.Id, model.UserRoles);

                    return RedirectToAction("Index", "Home");
                }

                // 返回注册页面时列出所有非“Admin”角色
                ViewBag.Name = new SelectList(context.Roles.Where(u => !u.Name.Contains("Admin"))
                                  .ToList(), "Name", "Name");

                AddErrors(result);
            }

            // 如果我们进行到这一步时某个地方出错,则重新显示表单
            return View(model);
        }

使用用户名进行登录

和用户注册时一样,我们通过输入用户名来替代默认输入Email的方式进行登录操作。

视图部分

修改Views/Account/Login.cshtml文件,将模型的Email属性替换为UserName属性。

Views/Account/Login.cshtml

@using UserRoleDemo.Models
@model LoginViewModel
@{
    ViewBag.Title = "登录";
}

<h2>@ViewBag.Title。</h2>
<div class="row">
    <div class="col-md-8">
        <section id="loginForm">
            @using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
            {
                @Html.AntiForgeryToken()
                <h4>使用本地帐户登录。</h4>
                <hr />
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                <!--替换Email为UserName-->
                <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" })
                        @Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
                    </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" })
                        @Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <div class="checkbox">
                            @Html.CheckBoxFor(m => m.RememberMe)
                            @Html.LabelFor(m => m.RememberMe)
                        </div>
                    </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>
                <p>
                    @Html.ActionLink("注册为新用户", "Register")
                </p>
                @* 在为密码重置功能启用帐户确认后启用此项
                    <p>
                        @Html.ActionLink("忘记了密码?", "ForgotPassword")
                    </p>*@
            }
        </section>
    </div>
    <div class="col-md-4">
        <section id="socialLoginForm">
            @Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl })
        </section>
    </div>
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

模型部分

和用户注册一样,在 AccountViewModel 中找到 LoginViewModel 并把 Email 替换为 UserName。

Models/AccountViewModels.cs(局部)

    public class LoginViewModel
    {
        [Required]
        [Display(Name = "用户名")]
        public string UserName { get; set; }

        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "密码")]
        public string Password { get; set; }

        [Display(Name = "记住我?")]
        public bool RememberMe { get; set; }
    }

控制器部分

在登录按钮的点击事件中我们同样需要把Email属性替换为 UserName来进行数据库认证。

Controllers/AccountController.cs(局部)

        //
        // POST: /Account/Login
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }

            // 这不会计入到为执行帐户锁定而统计的登录失败次数中
            // 若要在多次输入错误密码的情况下触发帐户锁定,请更改为 shouldLockout: true
            // 替换Email为UserName
            var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "无效的登录尝试。");
                    return View(model);
            }
        }

角色管理

角色模型为Microsoft.AspNet.Identity.EntityFramework.IdentityRole,本文中,我们使用ASP.NET Identity中的RoleManager对象进行角色管理。

控制器部分

首先,我们添加一个空的MVC5 控制器,命名为RoleController。

修改Controllers/RoleController.cs文件,增加Index、Create、Edit和Delete等ActionResult。

Controllers/RoleController.cs

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using UserRoleDemo.Models;

namespace UserRoleDemo.Controllers
{
    public class RoleController : Controller
    {
        private ApplicationDbContext context = new ApplicationDbContext();

        // GET: Role
        public ActionResult Index()
        {
            return View(context.Roles.ToList());
        }

        // GET: Role/Create
        public ActionResult Create()
        {
            return View();
        }

        // POST: Role/Create
        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
        // 详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkId=317598。
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "Id,Name")] IdentityRole identityRole)
        {
            if (ModelState.IsValid)
            {
                var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
                roleManager.Create(identityRole);

                return RedirectToAction("Index");
            }

            return View(identityRole);
        }

        // GET: Role/Edit/5
        public ActionResult Edit(string id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            IdentityRole identityRole = context.Roles.Find(id);
            if (identityRole == null)
            {
                return HttpNotFound();
            }
            return View(identityRole);
        }

        // POST: Role/Edit/5
        // 为了防止“过多发布”攻击,请启用要绑定到的特定属性,有关 
        // 详细信息,请参阅 https://go.microsoft.com/fwlink/?LinkId=317598。
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Include = "Id,Name")] IdentityRole identityRole)
        {
            if (ModelState.IsValid)
            {
                var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
                roleManager.Update(identityRole);

                return RedirectToAction("Index");
            }
            return View(identityRole);
        }

        // GET: Role/Delete/5
        public ActionResult Delete(string id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            IdentityRole identityRole = context.Roles.Find(id);
            if (identityRole == null)
            {
                return HttpNotFound();
            }
            return View(identityRole);
        }

        // POST: Role/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public ActionResult DeleteConfirmed(string id)
        {
            IdentityRole identityRole = context.Roles.Find(id);

            var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
            roleManager.Delete(identityRole);

            return RedirectToAction("Index");
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                context.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}

视图部分

分别在RoleController的ActionResult Index、Create、Edit、Delete上点击右键,选择 添加视图。

操作完成后,Views目录中应该会多出一个Role文件夹,其中包含Index.cshtml、Create.cshtml、Edit.cshtml和Delete.cshtml等4个视图文件。

Index

修改Views/Role/Index.cshtml,用于列出所有角色。

Views/Role/Index.cshtml

@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>
@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Name)
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.Id })
            </td>
        </tr>
    }

</table>

Create

Views/Role/Create.cshtml

@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>ApplicationUser</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Edit

Views/Role/Edit.cshtml

@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>ApplicationUser</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Delete

Views/Role/Delete.cshtml

@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@{
    ViewBag.Title = "Delete";
}

<h2>Delete</h2>

<h3>Are you sure you want to delete this?</h3>
<div>
    <h4>ApplicationUser</h4>
    <hr />
    <dl class="dl-horizontal">
        <dt>
            @Html.DisplayNameFor(model => model.Name)
        </dt>

        <dd>
            @Html.DisplayFor(model => model.Name)
        </dd>
    </dl>

    @using (Html.BeginForm())
    {
        @Html.AntiForgeryToken()

        <div class="form-actions no-color">
            <input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
        </div>
    }
</div>

扩展用户属性

启用 Entity Framework 合并

ASP.NET Identity 使用 Entity Framework Code First 作为基础框架,扩展用户属性就意味着我们需要修改Code First模型,因此,我们需要启用 Entity Framework 合并。

打开 程序包管理器控制台,在控制台窗口中输入 Enable-Migrations 并回车。

工具(T) - NuGet 包管理器(N) - 程序包管理器控制台(O)

添加扩展属性

在本文示例中我们为用户类新增一个 BirthDate 属性。

修改 ModelsIdentityModels.cs 文件,在ApplicationUser类定义中增加BirthDate属性。

ModelsIdentityModels.cs(局部)

    public class ApplicationUser : IdentityUser
    {
        [Display(Name = "生日")]
        public DateTime BirthDate { get; set; }

使用 Add-Migrations 命令修改数据库

由于我们为用户类添加了一个新属性,因此我们需要更新数据库来反映这个变化。

这也是EF 合并的真正用处所在。

还是在 程序包管理器控制台 中进行操作,

输入 Add-Migration "Birthdate"

该指令执行后将在项目中添加一个合并文件。

输入 Update-Database

该指令将运行所有合并文件并更新数据库以添加一个BirthDate 列

模型部分

修改ModelsAccountViewModels.cs 文件,将 BirthDate 添加到 RegisterViewModel

ModelsAccountViewModels.cs

    public class RegisterViewModel
    {
        [Required]
        [Display(Name = "所属角色")]
        public string UserRoles { get; set; }

        [Required]
        [Display(Name = "用户名")]
        public string UserName { get; set; }

        [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; }
        
        [Display(Name = "生日")]
        public DateTime BirthDate { get; set; }
    }

视图部分

更新 ViewsAccountRegister.cshtml 文件

ViewsAccountRegister.cshtml

@model UserRoleDemo.Models.RegisterViewModel
@{
    ViewBag.Title = "注册";
}

<h2>@ViewBag.Title。</h2>

@using (Html.BeginForm("Register", "Account", 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.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">
        @Html.Label("user Role", new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.DropDownList("UserRoles", (SelectList)ViewBag.Name, " ")
        </div>
    </div>
    <!--生日-->
    <div class="form-group">
        @Html.LabelFor(m => m.BirthDate, new { @class = "col-md-2 control-label" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.BirthDate, 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>
}

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

控制器部分

更新ControllersAccountController.cs 文件中的Register Action

ControllersAccountController.cs(局部)

var user = new ApplicationUser { UserName = model.UserName, Email = model.Email, BirthDate = model.BirthDate };

运行程序,再次注册用户时就可以看到BirthDate字段的应用。

针对Controller或Action的授权

ASP.NET Identity使用Authorize特性实现了针对Controller或Action的授权功能,实际上这个特性是MVC功能的一部分,被称为过滤器(Filter)。

过滤器(Filter)

ASP.NET MVC中把过滤器分为以下几类:

身份验证过滤器(IAuthenticationFilter)

这个过滤器是在MVC5中加入的,它是所有过滤器中优先级最高的,使用身份验证过滤器可以为Action、Controller或者所有的Controller添加身份验证逻辑。

授权过滤器(IAuthorizationFilter)

授权过滤器用来处理Controller以及Action的访问限制。

Action方法过滤器(IActionFilter)

Action过滤器可用于在Action方法执行前和执行后添加逻辑。

结果过滤器(IResultFilter)

结果过滤器可以在结果执行前和执行后添加逻辑。

ASP.NET MVC中的Action返回结果为ActionResult类型,该抽象类型定义了一个执行方法ExecuteResult,结果的执行实际上是对返回结果的处理

异常过滤器(IExceptionFilter)

异常过滤器就是Action方法在执行的过程中抛出异常时,用来添加异常处理逻辑的过滤器。

为RoleController设置过滤器

如果我们需要设置RoleController只允许角色为“Admin”的用户访问,则需要修改Controller/RoleController.cs文件,为RoleController设置过滤器。

Controller/RoleController.cs(局部)

    [Authorize(Order = 0, Roles = "Admin")]
    public class RoleController : Controller

为RoleController中的Create Action设置过滤器

只允许角色为“Admin”且用户名为“admin”的用户访问。

Controller/RoleController.cs(局部)

        // GET: Role/Create
        [Authorize(Order =1,Roles ="Admin",Users ="admin")]
        public ActionResult Create()
        {
            return View();
        }

结束语

本文仅就 ASP.NET Identity 的一些最为常用的功能进行了介绍,后续将逐步为大家介绍邮箱认证、短信认证、找回密码、第三方账号登录等功能,敬请期待。

参考文章

原文地址:https://www.cnblogs.com/mercator/p/11626912.html