ASP.NET MVC 安全与创建用户角色






4.94/5 (21投票s)
在本文中,我们将学习如何在 MVC 应用程序中使用 ASP.NET Identity 来创建用户角色,并根据用户角色显示菜单。
引言
一些成员要求我撰写一篇关于 ASP.NET MVC 安全的文章,所以我计划创建一系列文章。在这个系列中,我们将看到
- ASP.NET MVC 5 安全与创建用户角色
- 使用 WEB API 和 AngularJS 进行 ASP.NET MVC 基于用户角色的菜单管理。
在本文中,我们将学习如何在 MVC 应用程序中使用 ASP.NET Identity 来创建用户角色,并根据用户角色显示菜单。
在这里,我们将看到如何
- 创建默认管理员角色和其他角色。
- 创建默认管理员用户。
- 为新用户注册添加用户名。
- 在用户注册时选择用户角色。
- 使用用户名更改登录电子邮件。
- 仅为管理员用户显示角色创建菜单。
- 为普通用户显示消息。
- 将未经验证的用户重定向到默认主页。
身份验证和授权
身份验证
验证用户。这里的问题是如何检查用户是否有效。当用户第一次访问网站时,他会注册该网站。他所有的信息,如用户名、密码、电子邮件等,都会存储在网站数据库中。当用户输入他的用户ID和密码时,信息将与数据库进行检查。如果用户输入的用户名和密码与数据库中的相同,那么他就是一个有效用户,将被重定向到网站主页。如果用户输入的用户名和/或密码与数据库不匹配,则登录页面会显示一条消息,例如“请输入有效的名称或密码”。检查用户是否有效以及是否有权访问网站的整个过程称为身份验证。
Authorization
一旦用户通过身份验证,就需要根据其角色将其重定向到相应的页面。例如,当管理员登录时,他将被重定向到管理员页面。如果会计登录,他将被重定向到他的会计页面。如果普通用户登录,他将被重定向到他的页面。
必备组件
Visual Studio 2015: 您可以在 这里下载。
使用代码
在 Visual Studio 2015 中创建您的 Web 应用程序
安装完 Visual Studio 2015 后,单击“开始”,然后单击“程序”,选择 Visual Studio 2015。单击“新建”,然后单击“项目”,选择“Web”,然后选择 ASP.NET Web 应用程序。输入您的项目名称,然后单击“确定”。
选择 MVC,然后单击“确定”。
创建数据库
首先,我们将创建一个数据库,并在 web.config 文件中为 DefaultConnection 设置连接字符串,指向我们的新数据库。我们将使用此数据库来创建 ASP.NET Identity 表以及我们的示例考勤 Web 项目。我们不会使用两个数据库,一个用于默认 ASP.NET 用户数据库,另一个用于我们的考勤 DB,而是使用一个通用数据库来同时存储用户详细信息和我们示例 Web 项目演示。
-- =============================================
-- Author : Shanu
-- Create date : 2016-01-17
-- Description : To Create Database
-- =============================================
--Script to create DB,Table and sample Insert data
USE MASTER;
-- 1) Check for the Database Exists .If the database is exist then drop and create new DB
IF EXISTS (SELECT [name] FROM sys.databases WHERE [name] = 'AttendanceDB' )
BEGIN
ALTER DATABASE AttendanceDB SET SINGLE_USER WITH ROLLBACK IMMEDIATE
DROP DATABASE AttendanceDB ;
END
CREATE DATABASE AttendanceDB
GO
USE AttendanceDB
GO
在 web.config 文件中,我们可以找到 DefaultConnection 连接字符串。默认情况下,ASP.NET MVC 将使用此连接字符串创建所有 ASP.NET Identity 相关表,如 AspNetUsers 等。对于我们的应用程序,我们还需要使用数据库来处理其他页面的活动,而不是使用两个不同的数据库,一个用于用户详细信息,另一个用于我们自己的功能。在这里,我将使用一个数据库,其中将创建所有 ASP.NET Identity 表,并且我们还可以为其他页面使用创建自己的表。
<connectionStrings>
<add name="DefaultConnection" connectionString="data source=YOURSERVERNAME;initial catalog=AttendanceDB;user id=UID;password=PWD;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
首先,创建默认用户角色,例如“管理员”、“经理”等,我们还将创建一个默认管理员用户。我们将在“Startup.cs”中创建所有默认角色和用户。

参考
在“Startup.cs”文件中,我们可以找到 Configuration 方法。从这个方法,我们将调用我们的createRolesandUsers() 方法来创建一个默认的用户角色和用户。 我们将检查角色是否已创建。如果角色(例如管理员)尚未创建,那么我们将创建一个名为“管理员”的新角色,并创建一个默认用户并将用户角色设置为管理员。我们将使用此用户作为超级用户,该用户可以从我们的 MVC 应用程序创建新角色。
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
createRolesandUsers();
}
// In this method we will create default User roles and Admin user for login
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));
// In Startup iam creating first Admin Role and creating a default Admin User
if (!roleManager.RoleExists("Admin"))
{
// first we create Admin rool
var role = new Microsoft.AspNet.Identity.EntityFramework.IdentityRole();
role.Name = "Admin";
roleManager.Create(role);
//Here we create a Admin super user who will maintain the website
var user = new ApplicationUser();
user.UserName = "shanu";
user.Email = "syedshanumcain@gmail.com";
string userPWD = "A@Z200711";
var chkUser = UserManager.Create(user, userPWD);
//Add default User to Role Admin
if (chkUser.Succeeded)
{
var result1 = UserManager.AddToRole(user.Id, "Admin");
}
}
// creating Creating Manager role
if (!roleManager.RoleExists("Manager")) {
var role = new Microsoft.AspNet.Identity.EntityFramework.IdentityRole();
role.Name = "Manager";
roleManager.Create(role);
}
// creating Creating Employee role
if (!roleManager.RoleExists("Employee"))
{
var role = new Microsoft.AspNet.Identity.EntityFramework.IdentityRole();
role.Name = "Employee";
roleManager.Create(role);
}
}
当我们运行应用程序时,我们可以看到我们的 AttendanceDB 数据库中创建了新的默认 ASP.NET 用户相关表。在这里,我们可以看到下图,当运行应用程序时,所有 ASP.NET 用户相关的表都会自动创建,并且所有默认用户角色都会插入到 AspNetRoles 表中,默认管理员用户会创建到 AspNetUsers 表中。
自定义用户注册,添加用户名和角色
默认情况下,ASP.NET MVC 5 中的用户注册可以使用电子邮件和密码。在这里,我们将通过添加用户名和 ComboBox 来显示用户角色来定制默认用户注册。用户可以在注册时输入他们的用户名并选择他们的用户角色。
视图部分: 首先,在 Register.cshtml 中为用户名添加一个文本框,为显示用户角色添加一个 ComboBox
双击 Register.cshtml,并像下面这样更改 HTML 代码以添加带标题的文本框和组合框。在这里,我们可以看到我们首先添加一个文本框和组合框。我们将组合框绑定到 (SelectList) ViewBag.Name。
@model shanuMVCUserRoles.Models.RegisterViewModel
@{
ViewBag.Title = "Register";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("Register", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
@Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
@Html.ValidationSummary("", new { @class = "text-danger" })
<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.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.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("Name")*@
@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="Register" />
</div>
</div>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
模型部分
接下来,在 AccountViewModel.cs中检查 RegisterViewModel,并添加 UserRoles 和 UserName 属性,并添加必需的验证。
双击 Models 文件夹中的 AccountViewModel.cs 文件,找到 RegisterViewModel 类,添加 UserName 和 UserRoles 属性,如下所示。
public class RegisterViewModel
{
[Required]
[Display(Name = "UserRoles")]
public string UserRoles { get; set; }
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
控制器部分
接下来,在AccountController.cs file 中,我们首先获取所有要绑定到 ComboBox 的角色名称(不包括管理员角色),并在注册按钮点击时添加功能来插入用户名并设置 ASP.NET identity 数据库中的用户选定角色。
首先,为我们的 ApplicationDBContext 创建一个对象。这里,ApplicationDBContext 是一个类,用于执行所有 ASP.NET Identity 数据库功能,如创建用户、角色等。
ApplicationDbContext context;
public AccountController() {
context = new ApplicationDbContext();
}
Register ActionResult 方法:
使用 ApplicationDBConterxt 对象,我们将从数据库中获取所有角色。对于用户注册,我们将不显示管理员角色。用户可以在注册时选择任何其他类型的角色。
// 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 表中。在这里,我们将更改为存储用户输入的名称。用户成功创建后,我们将为用户设置用户选定的角色。
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
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);
// 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>");
//Assign Role to user Here
await this.UserManager.AddToRoleAsync(user.Id, model.UserRoles);
//Ends Here
return RedirectToAction("Index", "Users");
}
ViewBag.Name = new SelectList(context.Roles.Where(u => !u.Name.Contains("Admin"))
.ToList(), "Name", "Name");
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
自定义用户 登录
与用户注册一样,我们将自定义用户登录,以便更改电子邮件为用户名进行输入。默认情况下,ASP.NET MVC 5 登录时用户需要输入电子邮件和密码。在这里,我们将自定义为用户输入用户名和密码。在此演示中,我们不使用任何其他 Facebook、Gmail 或 Twitter 登录,因此我们将使用 UserName 而不是 Email。
视图部分
在这里,我们将更改 Login.cshtml 中的电子邮件为 UserName。我们可以在 Views/Account/Login.cshtml 文件夹中找到 Login.cshtml 文件。
@using shanuMVCUserRoles.Models
@model LoginViewModel
@{
ViewBag.Title = "Log in";
}
<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>Use a local account to log in.</h4>
<hr />
@Html.ValidationSummary(true, "", 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" })
@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="Log in" class="btn btn-default" />
</div>
</div>
<p>
@Html.ActionLink("Register as a new user", "Register")
</p>
@* Enable this once you have account confirmation enabled for password reset functionality
<p>
@Html.ActionLink("Forgot your password?", "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")
}
在下面的代码中,我们可以看到我们已经将 Email 属性更改为 UserName。
public class LoginViewModel
{
[Required]
[Display(Name = "UserName")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
}
控制器部分
在登录按钮点击时,我们需要将电子邮件更改为用户名,以便从数据库中检查用户身份验证。在这里,下面的代码可以看到,我们将电子邮件更改为用户名,在成功登录后,我们将重定向到用户页面。接下来,我们将看到如何创建用户页面并按用户角色显示文本和菜单。
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
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("", "Invalid login attempt.");
return View(model);
}
}
//
// GET: /Account/VerifyCode
[AllowAnonymous]
public async Task<ActionResult> VerifyCode(string provider, string returnUrl, bool rememberMe)
{
// Require that the user has already logged in via username/password or external login
if (!await SignInManager.HasBeenVerifiedAsync())
{
return View("Error");
}
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
}
已认证和已授权用户页面
在这里,我们创建一个新页面来显示已认证和已授权用户的消息,按其角色划分。
如果登录用户的角色是管理员,那么我们将显示管理员的欢迎消息并显示创建新角色的菜单。
如果登录用户的角色是经理、员工、会计等,那么我们将显示他们的欢迎消息。
首先,创建一个名为“userscontroller.cs”的新空控制器。在此控制器中,我们首先在控制器顶部添加 [Authorize] 以检查有效用户。
创建我们的视图:右键单击 index ActionResult 并创建一个视图。
在视图中,我们检查 ViewBag.displayMenu 值。如果值为“Yes",那么我们显示管理员欢迎消息和创建新菜单的链接。如果 ViewBag.displayMenu 为“No",那么显示其他用户的姓名和欢迎消息。
@{
ViewBag.Title = "Index";
}
@if (ViewBag.displayMenu == "Yes")
{
<h1>Welcome Admin. Now you can create user Role.</h1>
<h3>
<li>@Html.ActionLink("Manage Role", "Index", "Role")</li>
</h3>
}
else
{
<h2> Welcome <strong>@ViewBag.Name</strong> :) .We will add user module soon </h2>
}
控制器部分
在控制器中,我们将检查用户是否已登录到系统。如果用户未登录,我们
显示消息“未登录”。如果用户已认证,那么我们将检查登录用户的角色。如果用户角色是“管理员”,那么我们将设置ViewBag.displayMenu = "Yes"
,否则我们设置ViewBag.displayMenu = "No"
。
public ActionResult Index()
{
if (User.Identity.IsAuthenticated)
{
var user = User.Identity;
ViewBag.Name = user.Name;
ViewBag.displayMenu = "No";
if (isAdminUser())
{
ViewBag.displayMenu = "Yes";
}
return View();
}
else
{
ViewBag.Name = "Not Logged IN";
}
return View();
}
为了检查用户是否已登录,我们创建一个方法并将布尔值返回给我们的主 Index 方法。
public Boolean isAdminUser()
{
if (User.Identity.IsAuthenticated)
{
var user = User.Identity;
ApplicationDbContext context = new ApplicationDbContext();
var UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(context));
var s = UserManager.GetRoles(user.GetUserId());
if (s[0].ToString() == "Admin")
{
return true;
}
else
{
return false;
}
}
return false;
}
管理员用户可以创建角色
我们已经看到,如果管理员用户登录,那么我们将显示创建新用户的链接。对于管理员登录,我们已经创建了一个默认用户,用户名为“shanu”,密码为“A@Z200711”。
为了让管理员创建用户角色,首先我们将添加一个新的空控制器,并将其命名为 RoleController.cs,
在此控制器中,我们检查用户角色是否为管理员。如果登录用户的角色是管理员,那么我们将使用 ApplicationDbContext 对象获取所有角色名称。
public ActionResult Index()
{
if (User.Identity.IsAuthenticated)
{
if (!isAdminUser())
{
return RedirectToAction("Index", "Home");
}
}
else
{
return RedirectToAction("Index", "Home");
}
var Roles = context.Roles.ToList();
return View(Roles);
}
在视图中,我们将所有用户角色绑定到 HTML 表中。
@model IEnumerable<Microsoft.AspNet.Identity.EntityFramework.IdentityRole>
@{
ViewBag.Title = "Add Role";
}
<table style=" background-color:#FFFFFF; border: dashed 3px #6D7B8D; padding: 5px;width: 99%;table-layout:fixed;" cellpadding="6" cellspacing="6">
<tr style="height: 30px; background-color:#336699 ; color:#FFFFFF ;border: solid 1px #659EC7;">
<td align="center" colspan="2">
<h2> Create User Roles</h2>
</td>
</tr>
<tr>
<td>
<table id="tbrole" style="width:100%; border:dotted 1px; background-color:gainsboro; padding-left:10px;">
@foreach (var item in Model)
{
<tr>
<td style="width:100%; border:dotted 1px;">
@item.Name
</td>
</tr>}
</table>
</td>
<td align="right" style="color:#FFFFFF;padding-right:10;">
<h3> @Html.ActionLink("Click to Create New Role", "Create", "Role") </h3>
</td>
</tr>
</table>
关注点
首先,在 SQL Server 中创建一个名为 AttendanceDB 的示例数据库。在 Web.Config 文件中,将 DefaultConnection 连接字符串更改为您的 SQL Server 连接。在 Startup.cs 文件中,我创建了一个默认的管理员用户,用户名为“shanu”,密码为“A@Z200711”。此用户名和密码将用于以管理员身份登录。您可以根据需要更改此用户名和密码。出于安全原因,以管理员身份登录后,您可以随意更改管理员用户的密码。
历史
shanuMVCUserRoles.zip - 2016-01-29。