在本章中,我们将讨论如何在应用程序中实现安全功能。还将看到ASP.NET中包含的新成员特性,并可从ASP.NET MVC中使用。在ASP.NET的最新版本中,可以通过以下方式管理用户身份 -
- 云
- SQL数据库
- 本地Windows活动目录
在本章中,我们将介绍作为ASP.NET一部分的新身份组件,并了解如何自定义用户和角色的成员资格。
认证
用户的认证意味着验证用户的身份,这真的很重要。可能需要将您的应用程序仅显示给经过身份验证的用户,原因很明显。
我们来创建一个新的ASP.Net MVC应用程序项目:MVCSecurity 。点击确定 继续。
当启动一个新的ASP.NET应用程序时,这个过程中的一个步骤就是为应用程序需要配置身份验证服务。选择MVC模板,将看到现在启用了更改认证按钮。
这是通过出现在“新建项目”对话框中的“更改认证”按钮完成的。默认身份验证是个人用户帐户。
认证选项
当单击更改按钮时,您将看到一个对话框,其中包含四个选项,如下所示。
1. 不进行身份验证
第一个选项是不验证,当想建立一个不关心访问者是谁的网站时使用这个选项。
它是开放给任何人和每个人连接为每一个页面。以后可以随时更改,但“不进行身份验证” 选项意味着不会有任何功能来识别访问该网站的用户。
2. 个人用户帐户
第二个选项是个人用户帐户,这是用户可以访问网站的传统的基于表单的身份验证。 他们可以注册,创建一个登录名,默认情况下,用户名是使用一些新的ASP.NET身份特性存储在SQL Server数据库中。
密码也存储在数据库中,但首先被散列。由于密码是散列的,因此不必担心在数据库中的纯文本密码而被别人知道。
此选项通常用于要建立用户身份的Internet站点。 除了允许用户使用网站的密码创建本地登录外,还可以启用来自Microsoft,Google,Facebook和Twitter等第三方的登录。
这允许用户使用他们的真实帐户或他们的Twitter帐户登录到您的网站,但是您不需要存储任何密码。
这将在这个模块中花费一些时间的选项。个人用户帐户 选项。
3. 工作和学校帐户
第三个选择是使用组织帐户,这通常用于使用活动目录联合服务的业务应用程序。
将设置Office 365或使用Azure Active Directory服务,并且您有内部应用程序和云应用程序的单一登录。
您还需要提供应用程序ID,以便应用程序需要在Windows Azure管理门户(如果这是基于Azure的)上进行注册,并且应用程序ID将在所有可能注册的应用程序中唯一标识此应用程序。
4. Windows身份验证
第四个选项是Windows身份验证 ,适用于Intranet应用程序。
用户登录到Windows桌面,并可以将浏览器启动到位于同一防火墙内的应用程序。 ASP.NET可以自动获取用户的身份,即由活动目录建立的身份。 该选项不允许任何匿名访问该站点,但这也是一个可以更改的配置设置。
下面我们来看看基于表单的身份验证 ,即名称为个人用户帐户的身份验证。 此应用程序将用户名和密码,旧密码存储在本地SQL Server数据库中,创建此项目时,Visual Studio也将添加NuGet包。
现在运行这个应用程序,当您第一次访问这个应用程序,那么是以一个匿名用户来访问的。
因为您还没有登录的账户,所以需要在这个网站上先注册一个用户。
点击注册 链接,会看到下面的视图。
输入您的电子邮件ID和密码,例如:maxsu@xuhuhu.com
和Abc@123
。
点击注册。 现在,应用程序将使用此账户信息识别您。
它将能够显示用户的名字。 在下面的截图中,可以看到:“你好,maxsu@xuhuhu.com!” 。 可以点击它链接到一个页面,可以在这个页面中更改密码。
也可以注销,关闭,重新启动,一个星期后回来,应该可以使用之前使用的凭据登录。现在点击注销 按钮,它将显示以下页面。再次点击登录链接进入下一页。可以使用相同的凭据重新登录。
很多工作都在幕后进行到现在。 但是,我们想要做的是检查每个功能,看看这个UI是如何构建的。 什么是管理注销和登录过程? 这些信息在数据库中排序?
让我们从一些简单的基础开始。 首先,我们将看到这个用户名是如何显示的。 从解决方案资源管理器中的View/Shared文件夹中打开_Layout.cshtml
。
<!DOCTYPE html>
<html>
<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>@ViewBag.Title - 我的 ASP.NET 应用程序</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("应用程序名称", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("主页", "Index", "Home")</li>
<li>@Html.ActionLink("关于", "About", "Home")</li>
<li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - 我的 ASP.NET 应用程序</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
有一个共同的导航栏,应用程序名称,菜单,并有一个局部视图呈现为_loginpartial
。 这实际上是显示用户名或注册和登录名的视图。 所以_loginpartial.cshtml
也在shared文件夹中。其代码如下所示 -
@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav navbar-right">
<li>
@Html.ActionLink("你好," + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
<li><a href="javascript:document.getElementById('logoutForm').submit()">注销</a></li>
</ul>
}
}
else
{
<ul class="nav navbar-nav navbar-right">
<li>@Html.ActionLink("注册", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
<li>@Html.ActionLink("登录", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
正如可以看到上面,有if/else
语句。 如果请求没有被认证,这个视图将显示注册和登录链接。用户可以点击链接登录或注册。所有这些都是由帐户控制器完成的。
现在,我们想看看如何获取用户名,这是在Request.IsAuthenticated
。 可以看到对User.Identity.GetUserName
的调用。这将检索用户名,在这种情况下是"maxsu@xuhuhu.com"
授权
假设想要防止未经验证的用户的信息。 因此,让我们创建一个新的控制器来显示这些信息,但只有当用户登录时才能操作。
右键单击Controllers 文件夹,然后选择:添加 -> 控制器 。选择一个MVC 5控制器 - 空 控制器,然后点击“添加”。输入名称SecretController,然后单击“添加” 按钮。
它将会有两个动作,如下面的代码所示。参考以下代码 -
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVCSecurity.Controllers
{
public class SecretController : Controller
{
// GET: Secret
public ActionResult Index()
{
return View();
}
// GET: Secret
public ContentResult Secret()
{
return Content("Secret informations here");
}
public ContentResult PublicInfo()
{
return Content("Public informations here");
}
}
}
当运行这个应用程序时,可以在没有任何验证的情况下访问这个信息(URL:http://localhost:57742/Secret/Secret
),如下面的截图所示。
假设只有经过身份验证的用户才能够使用Secret
动作方法,并且任何人都可以使用PublicInfo
,而不需要任何身份验证。
为了保护这个特定的操作并保证未经身份验证的用户到达此处,可以使用Authorize
属性。 没有任何其他参数的授权属性将确保用户的身份是已知的,他们不是一个匿名用户。
// GET: Secret
[Authorize]
public ContentResult Secret(){
return Content("Secret informations here");
}
现在再次运行这个应用程序,并指定相同的URL:http://localhost:57742/Secret/Secret
。 MVC应用程序将检测到您无权访问应用程序的特定区域,并且会自动重定向到登录页面,在那里登录并尝试返回访问受限的应用程序的URL。
可以看到它在返回URL中指定,它告诉此页面,如果用户成功登录,则将其重定向到/secret/secret
。
输入您的用户名和密码,然后点击“登录”按钮。会看到它直接进入该页面。
当不想在每一个动作上进行授权的时候,当想要在一个控制器里,几乎所有的事情都需要授权。 在这种情况下,总是可以将此过滤器应用于控制器本身,现在,此控制器内部的每个操作都将要求用户进行身份验证。
using System.Web.Mvc;
namespace MVCSecurityDemo.Controllers{
[Authorize]
public class SecretController : Controller{
// GET: Secret
public ContentResult Secret(){
return Content("Secret informations here");
}
public ContentResult PublicInfo(){
return Content("Public informations here");
}
}
}
但是,如果想要任何人都可以打开某一个操作,则可以使用另一个属性(即AllowAnonymous
)覆盖此授权规则。参考以下代码 -
using System.Web.Mvc;
namespace MVCSecurityDemo.Controllers{
[Authorize]
public class SecretController : Controller{
// GET: Secret
public ContentResult Secret(){
return Content("Secret informations here");
}
[AllowAnonymous]
public ContentResult PublicInfo(){
return Content("Public informations here");
}
}
}
使用Authorize
属性,也可以指定一些参数,比如允许一些特定的用户进入这个动作。
using System.Web.Mvc;
namespace MVCSecurityDemo.Controllers{
[Authorize(Users = "maxsu@xuhuhu.com")]
public class SecretController : Controller{
// GET: Secret
public ContentResult Secret(){
return Content("Secret informations here");
}
[AllowAnonymous]
public ContentResult PublicInfo(){
return Content("Public informations here");
}
}
}
当运行此应用程序并转到URL:/secret/secret
时,如果它不是此控制器要求的用户(maxsu@xuhuhu.com
),它会要求您登录。