在本章中,我們將討論如何在應(yīng)用程序中實現(xiàn)安全功能。還將看到ASP.NET中包含的新成員特性,并可從ASP.NET MVC中使用。在ASP.NET的最新版本中,可以通過以下方式管理用戶身份 -
在本章中,我們將介紹作為ASP.NET一部分的新身份組件,并了解如何自定義用戶和角色的成員資格。
用戶的認(rèn)證意味著驗證用戶的身份,這真的很重要??赡苄枰獙⒛膽?yīng)用程序僅顯示給經(jīng)過身份驗證的用戶,原因很明顯。
我們來創(chuàng)建一個新的ASP.Net MVC應(yīng)用程序項目:MVCSecurity 。點擊確定 繼續(xù)。
當(dāng)啟動一個新的ASP.NET應(yīng)用程序時,這個過程中的一個步驟就是為應(yīng)用程序需要配置身份驗證服務(wù)。選擇MVC模板,將看到現(xiàn)在啟用了更改認(rèn)證按鈕。
這是通過出現(xiàn)在“新建項目”對話框中的“更改認(rèn)證”按鈕完成的。默認(rèn)身份驗證是個人用戶帳戶。
當(dāng)單擊更改按鈕時,您將看到一個對話框,其中包含四個選項,如下所示。
第一個選項是不驗證,當(dāng)想建立一個不關(guān)心訪問者是誰的網(wǎng)站時使用這個選項。
它是開放給任何人和每個人連接為每一個頁面。以后可以隨時更改,但“不進(jìn)行身份驗證” 選項意味著不會有任何功能來識別訪問該網(wǎng)站的用戶。
第二個選項是個人用戶帳戶,這是用戶可以訪問網(wǎng)站的傳統(tǒng)的基于表單的身份驗證。 他們可以注冊,創(chuàng)建一個登錄名,默認(rèn)情況下,用戶名是使用一些新的ASP.NET身份特性存儲在SQL Server數(shù)據(jù)庫中。
密碼也存儲在數(shù)據(jù)庫中,但首先被散列。由于密碼是散列的,因此不必?fù)?dān)心在數(shù)據(jù)庫中的純文本密碼而被別人知道。
此選項通常用于要建立用戶身份的Internet站點。 除了允許用戶使用網(wǎng)站的密碼創(chuàng)建本地登錄外,還可以啟用來自Microsoft,Google,F(xiàn)acebook和Twitter等第三方的登錄。
這允許用戶使用他們的真實帳戶或他們的Twitter帳戶登錄到您的網(wǎng)站,但是您不需要存儲任何密碼。
這將在這個模塊中花費一些時間的選項。個人用戶帳戶 選項。
第三個選擇是使用組織帳戶,這通常用于使用活動目錄聯(lián)合服務(wù)的業(yè)務(wù)應(yīng)用程序。
將設(shè)置Office 365或使用Azure Active Directory服務(wù),并且您有內(nèi)部應(yīng)用程序和云應(yīng)用程序的單一登錄。
您還需要提供應(yīng)用程序ID,以便應(yīng)用程序需要在Windows Azure管理門戶(如果這是基于Azure的)上進(jìn)行注冊,并且應(yīng)用程序ID將在所有可能注冊的應(yīng)用程序中唯一標(biāo)識此應(yīng)用程序。
第四個選項是Windows身份驗證 ,適用于Intranet應(yīng)用程序。
用戶登錄到Windows桌面,并可以將瀏覽器啟動到位于同一防火墻內(nèi)的應(yīng)用程序。 ASP.NET可以自動獲取用戶的身份,即由活動目錄建立的身份。 該選項不允許任何匿名訪問該站點,但這也是一個可以更改的配置設(shè)置。
下面我們來看看基于表單的身份驗證 ,即名稱為個人用戶帳戶的身份驗證。 此應(yīng)用程序?qū)⒂脩裘兔艽a,舊密碼存儲在本地SQL Server數(shù)據(jù)庫中,創(chuàng)建此項目時,Visual Studio也將添加NuGet包。
現(xiàn)在運行這個應(yīng)用程序,當(dāng)您第一次訪問這個應(yīng)用程序,那么是以一個匿名用戶來訪問的。
因為您還沒有登錄的賬戶,所以需要在這個網(wǎng)站上先注冊一個用戶。
點擊注冊 鏈接,會看到下面的視圖。
輸入您的電子郵件ID和密碼,例如:maxsu@yiibai.com
和Abc@123
。
點擊注冊。 現(xiàn)在,應(yīng)用程序?qū)⑹褂么速~戶信息識別您。
它將能夠顯示用戶的名字。 在下面的截圖中,可以看到:“你好,maxsu@yiibai.com!” 。 可以點擊它鏈接到一個頁面,可以在這個頁面中更改密碼。
也可以注銷,關(guān)閉,重新啟動,一個星期后回來,應(yīng)該可以使用之前使用的憑據(jù)登錄?,F(xiàn)在點擊注銷 按鈕,它將顯示以下頁面。再次點擊登錄鏈接進(jìn)入下一頁??梢允褂孟嗤膽{據(jù)重新登錄。
很多工作都在幕后進(jìn)行到現(xiàn)在。 但是,我們想要做的是檢查每個功能,看看這個UI是如何構(gòu)建的。 什么是管理注銷和登錄過程? 這些信息在數(shù)據(jù)庫中排序?
讓我們從一些簡單的基礎(chǔ)開始。 首先,我們將看到這個用戶名是如何顯示的。 從解決方案資源管理器中的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 應(yīng)用程序</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("應(yīng)用程序名稱", "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("關(guān)于", "About", "Home")</li>
<li>@Html.ActionLink("聯(lián)系方式", "Contact", "Home")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>? @DateTime.Now.Year - 我的 ASP.NET 應(yīng)用程序</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
有一個共同的導(dǎo)航欄,應(yīng)用程序名稱,菜單,并有一個局部視圖呈現(xiàn)為_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
語句。 如果請求沒有被認(rèn)證,這個視圖將顯示注冊和登錄鏈接。用戶可以點擊鏈接登錄或注冊。所有這些都是由帳戶控制器完成的。
現(xiàn)在,我們想看看如何獲取用戶名,這是在Request.IsAuthenticated
。 可以看到對User.Identity.GetUserName
的調(diào)用。這將檢索用戶名,在這種情況下是"maxsu@yiibai.com"
假設(shè)想要防止未經(jīng)驗證的用戶的信息。 因此,讓我們創(chuàng)建一個新的控制器來顯示這些信息,但只有當(dāng)用戶登錄時才能操作。
右鍵單擊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");
}
}
}
當(dāng)運行這個應(yīng)用程序時,可以在沒有任何驗證的情況下訪問這個信息(URL:http://localhost:57742/Secret/Secret
),如下面的截圖所示。
假設(shè)只有經(jīng)過身份驗證的用戶才能夠使用Secret
動作方法,并且任何人都可以使用PublicInfo
,而不需要任何身份驗證。
為了保護(hù)這個特定的操作并保證未經(jīng)身份驗證的用戶到達(dá)此處,可以使用Authorize
屬性。 沒有任何其他參數(shù)的授權(quán)屬性將確保用戶的身份是已知的,他們不是一個匿名用戶。
// GET: Secret
[Authorize]
public ContentResult Secret(){
return Content("Secret informations here");
}
現(xiàn)在再次運行這個應(yīng)用程序,并指定相同的URL:http://localhost:57742/Secret/Secret
。 MVC應(yīng)用程序?qū)z測到您無權(quán)訪問應(yīng)用程序的特定區(qū)域,并且會自動重定向到登錄頁面,在那里登錄并嘗試返回訪問受限的應(yīng)用程序的URL。
可以看到它在返回URL中指定,它告訴此頁面,如果用戶成功登錄,則將其重定向到/secret/secret
。
輸入您的用戶名和密碼,然后點擊“登錄”按鈕。會看到它直接進(jìn)入該頁面。
當(dāng)不想在每一個動作上進(jìn)行授權(quán)的時候,當(dāng)想要在一個控制器里,幾乎所有的事情都需要授權(quán)。 在這種情況下,總是可以將此過濾器應(yīng)用于控制器本身,現(xiàn)在,此控制器內(nèi)部的每個操作都將要求用戶進(jìn)行身份驗證。
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
)覆蓋此授權(quán)規(guī)則。參考以下代碼 -
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
屬性,也可以指定一些參數(shù),比如允許一些特定的用戶進(jìn)入這個動作。
using System.Web.Mvc;
namespace MVCSecurityDemo.Controllers{
[Authorize(Users = "maxsu@yiibai.com")]
public class SecretController : Controller{
// GET: Secret
public ContentResult Secret(){
return Content("Secret informations here");
}
[AllowAnonymous]
public ContentResult PublicInfo(){
return Content("Public informations here");
}
}
}
當(dāng)運行此應(yīng)用程序并轉(zhuǎn)到URL:/secret/secret
時,如果它不是此控制器要求的用戶(maxsu@yiibai.com
),它會要求您登錄。