在本章中,我們將討論如何在應用程式中實現安全功能。還將看到ASP.NET中包含的新成員特性,並可從ASP.NET MVC中使用。在ASP.NET的最新版本中,可以通過以下方式管理使用者身份 -
在本章中,我們將介紹作為ASP.NET一部分的新身份元件,並了解如何自定義使用者和角色的成員資格。
使用者的認證意味著驗證使用者的身份,這真的很重要。可能需要將您的應用程式僅顯示給經過身份驗證的使用者,原因很明顯。
我們來建立一個新的ASP.Net MVC應用程式專案:MVCSecurity 。點選確定 繼續。
當啟動一個新的ASP.NET應用程式時,這個過程中的一個步驟就是為應用程式需要組態身份驗證服務。選擇MVC模板,將看到現在啟用了更改認證按鈕。
這是通過出現在「新建專案」對話方塊中的「更改認證」按鈕完成的。預設身份驗證是個人使用者帳戶。
當單擊更改按鈕時,您將看到一個對話方塊,其中包含四個選項,如下所示。
第一個選項是不驗證,當想建立一個不關心存取者是誰的網站時使用這個選項。
它是開放給任何人和每個人連線為每一個頁面。以後可以隨時更改,但「不進行身份驗證」 選項意味著不會有任何功能來識別存取該網站的使用者。
第二個選項是個人使用者帳戶,這是使用者可以存取網站的傳統的基於表單的身份驗證。 他們可以註冊,建立一個登入名,預設情況下,使用者名是使用一些新的ASP.NET身份特性儲存在SQL Server資料庫中。
密碼也儲存在資料庫中,但首先被雜湊。由於密碼是雜湊的,因此不必擔心在資料庫中的純文字密碼而被別人知道。
此選項通常用於要建立使用者身份的Internet站點。 除了允許使用者使用網站的密碼建立本地登入外,還可以啟用來自Microsoft,Google,Facebook和Twitter等第三方的登入。
這允許使用者使用他們的真實帳戶或他們的Twitter帳戶登入到您的網站,但是您不需要儲存任何密碼。
這將在這個模組中花費一些時間的選項。個人使用者帳戶 選項。
第三個選擇是使用組織帳戶,這通常用於使用活動目錄聯合服務的業務應用程式。
將設定Office 365或使用Azure Active Directory服務,並且您有內部應用程式和雲應用程式的單一登入。
您還需要提供應用程式ID,以便應用程式需要在Windows Azure管理門戶(如果這是基於Azure的)上進行註冊,並且應用程式ID將在所有可能註冊的應用程式中唯一標識此應用程式。
第四個選項是Windows身份驗證 ,適用於Intranet應用程式。
使用者登入到Windows桌面,並可以將瀏覽器啟動到位於同一防火牆內的應用程式。 ASP.NET可以自動獲取使用者的身份,即由活動目錄建立的身份。 該選項不允許任何匿名存取該站點,但這也是一個可以更改的組態設定。
下面我們來看看基於表單的身份驗證 ,即名稱為個人使用者帳戶的身份驗證。 此應用程式將使用者名和密碼,舊密碼儲存在本地SQL Server資料庫中,建立此專案時,Visual Studio也將新增NuGet包。
現在執行這個應用程式,當您第一次存取這個應用程式,那麼是以一個匿名使用者來存取的。
因為您還沒有登入的賬戶,所以需要在這個網站上先註冊一個使用者。
點選註冊 連結,會看到下面的檢視。
輸入您的電子郵件ID和密碼,例如:[email protected]
和Abc@123
。
點選註冊。 現在,應用程式將使用此賬戶資訊識別您。
它將能夠顯示使用者的名字。 在下面的截圖中,可以看到:「你好,[email protected]!」 。 可以點選它連結到一個頁面,可以在這個頁面中更改密碼。
也可以登出,關閉,重新啟動,一個星期後回來,應該可以使用之前使用的憑據登入。現在點選登出 按鈕,它將顯示以下頁面。再次點選登入連結進入下一頁。可以使用相同的憑據重新登入。
很多工作都在幕後進行到現在。 但是,我們想要做的是檢查每個功能,看看這個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
的呼叫。這將檢索使用者名,在這種情況下是"[email protected]"
假設想要防止未經驗證的使用者的資訊。 因此,讓我們建立一個新的控制器來顯示這些資訊,但只有當使用者登入時才能操作。
右鍵單擊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 = "[email protected]")]
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
時,如果它不是此控制器要求的使用者([email protected]
),它會要求您登入。