ASP.NET MVC - 安全性



在本章中,我們將討論如何在應用程式中實現安全功能。我們還將瞭解 ASP.NET 中包含的新成員資格功能,以及可供 ASP.NET MVC 使用的功能。在 ASP.NET 的最新版本中,我們可以使用以下方式管理使用者標識:

  • SQL 資料庫
  • 本地 Windows 活動目錄

在本章中,我們還將瞭解作為 ASP.NET 一部分的新身份元件,並瞭解如何為我們的使用者和角色自定義成員資格。

身份驗證

使用者身份驗證是指驗證使用者身份。這非常重要。出於顯而易見的原因,您可能需要僅向已驗證的使用者展示您的應用程式。

讓我們建立一個新的 ASP.Net MVC 應用程式。

New MVC Application

單擊“確定”繼續。

當您啟動一個新的 ASP.NET 應用程式時,該過程中的一個步驟是為應用程式需求配置身份驗證服務。

選擇 MVC 模板,您會看到“更改身份驗證”按鈕現在已啟用。

Authentication Button Enabled

這是透過“新建專案”對話方塊中出現的“更改身份驗證”按鈕完成的。預設身份驗證為“單個使用者帳戶”。

身份驗證選項

單擊“更改”按鈕時,您將看到一個帶有四個選項的對話方塊,如下所示。

無身份驗證

第一個選項是“無身份驗證”,當您想要構建一個不關心訪問者是誰的網站時,可以使用此選項。

No Authentication

它對所有人開放,每個人都連線到每個頁面。您始終可以稍後更改它,但“無身份驗證”選項意味著不會有任何功能來識別訪問網站的使用者。

單個使用者帳戶

第二個選項是“單個使用者帳戶”,這是傳統的基於表單的身份驗證,使用者可以訪問網站。他們可以註冊、建立登入名,並且預設情況下,他們的使用者名稱使用一些新的 ASP.NET 身份功能儲存在 SQL Server 資料庫中,我們將在後面介紹。

Individual User Accounts

密碼也儲存在資料庫中,但首先會進行雜湊處理。由於密碼已進行雜湊處理,因此您無需擔心資料庫中存在明文密碼。

此選項通常用於您想要建立使用者身份的網際網路站點。除了允許使用者為您的站點建立本地登入名和密碼外,您還可以啟用來自第三方(如 Microsoft、Google、Facebook 和 Twitter)的登入。

這允許使用者使用他們的 Live 帳戶或 Twitter 帳戶登入到您的站點,並且他們可以選擇本地使用者名稱,但您無需儲存任何密碼。

這是我們將在本模組中花費一些時間討論的選項;“單個使用者帳戶”選項。

工作和學校帳戶

第三個選項是使用組織帳戶,這通常用於您將使用活動目錄聯合服務的業務應用程式。

Work School Accounts

您將設定 Office 365 或使用 Azure Active Directory 服務,並且您擁有內部應用程式和雲應用程式的單點登入。

您還需要提供應用程式 ID,因此如果基於 Azure,則需要在 Windows Azure 管理門戶中註冊您的應用程式,並且應用程式 ID 將在所有可能註冊的應用程式中唯一標識此應用程式。

Windows 身份驗證

第四個選項是 Windows 身份驗證,它適用於內聯網應用程式。

Windows Authentication

使用者登入到 Windows 桌面,然後可以啟動瀏覽器訪問位於同一防火牆內的應用程式。ASP.NET 可以自動獲取使用者身份,即由活動目錄建立的身份。此選項不允許任何匿名訪問站點,但這又是可以更改的配置設定。

讓我們看看基於表單的身份驗證,即名為“單個使用者帳戶”的身份驗證。此應用程式將儲存使用者名稱和密碼、舊密碼在本地 SQL Server 資料庫中,並且在建立此專案時,Visual Studio 還會新增 NuGet 包。

Forms-based Authentication

現在執行此應用程式,當您第一次訪問此應用程式時,您將是匿名使用者。

Anonymous User

您還沒有可以登入的帳戶,因此您需要在此站點上註冊。

單擊“註冊”連結,您將看到以下檢視。

Click Register Link

輸入您的電子郵件 ID 和密碼。

Enter EmailId Password

單擊“註冊”。現在,應用程式將識別您。

Click Register

它將能夠顯示您的姓名。在下面的螢幕截圖中,您可以看到顯示了“您好,muhammad.waqas@outlook.com!”。您可以單擊它,它是一個連結到您可以更改密碼的頁面的連結。

Display Your Name

您還可以登出、關閉、重新啟動,一週後再回來,您應該能夠使用之前使用的憑據登入。現在單擊“登出”按鈕,它將顯示以下頁面。

Click Logoff Button

再次單擊“登入”連結,您將轉到以下頁面。

Click Login Link

您可以使用相同的憑據再次登入。

幕後做了很多工作才能達到這一點。但是,我們要做的是檢查每個功能並瞭解此 UI 是如何構建的。是什麼管理登出和登入過程?此資訊儲存在資料庫中的哪個位置?

讓我們從幾個簡單的基礎開始。首先,我們將瞭解如何顯示此使用者名稱。在解決方案資源管理器中開啟“檢視/共享”資料夾中的 _Layout.cshtml。

<!DOCTYPE html>
<html>
   <head>
      <meta charset = "utf-8" />
      <meta name = "viewport" content = "width = device-width, initial-scale = 1.0">
      <title>@ViewBag.Title - My ASP.NET Application</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" datatoggle = "collapse"
                  data-target = ".navbar-collapse">
                     <span class = "icon-bar"></span>
                     <span class = "icon-bar"></span>
                     <span class = "icon-bar"></span>
               </button>
					
               @Html.ActionLink("Application name", "Index", "Home", new
               { area = "" }, new { @class = "navbar-brand" })
            </div>
				
            <div class = "navbar-collapse collapse">
               <ul class = "nav navbar-nav">
                  <li>@Html.ActionLink("Home", "Index", "Home")</li>
                  <li>@Html.ActionLink("About", "About", "Home")</li>
                  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
               </ul>
					
               @Html.Partial("_LoginPartial")
            </div>
				
         </div>
			
      </div>
      <div class = "container body-content">
         @RenderBody()
         <hr />
         <footer>
            <p>© @DateTime.Now.Year - My ASP.NET Application</p>
         </footer>
      </div>
		
      @Scripts.Render("~/bundles/jquery")
      @Scripts.Render("~/bundles/bootstrap")
      @RenderSection("scripts", required: false)
		
   </body>
</html>

有一個公共導航欄、應用程式名稱、選單,以及一個名為 _loginpartial 的正在呈現的部分檢視。這實際上是顯示使用者名稱或註冊和登入名的檢視。因此 _loginpartial.cshtml 也在共享資料夾中。

@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("Hello " + User.Identity.GetUserName() + "!",
               "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
            </li>
				
            <li>
               <a href = "javascript:document.getElementById('logoutForm').submit()">Logoff</a>
            </li>
				
         </ul>
      }
}else{
   <ul class = "nav navbar-nav navbar-right">
      <li>@Html.ActionLink("Register", "Register", "Account", routeValues:
         null, htmlAttributes: new { id = "registerLink" })</li>
			
      <li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null,
         htmlAttributes: new { id = "loginLink" })</li>
   </ul>
}

如上所示,存在 if/else 語句。如果我們不知道使用者是誰,因為請求未經身份驗證,則此檢視將顯示註冊和登入連結。使用者可以單擊連結登入或註冊。所有這些都是由帳戶控制器完成的。

現在,我們要了解如何獲取使用者名稱,它位於 Request.IsAuthenticated 內部。您可以看到對 User.Identity.GetUserName 的呼叫。這將檢索使用者名稱,在本例中為“muhammad.waqas@outlook.com”

授權

假設我們有一些我們想要保護免遭未經身份驗證的使用者訪問的資訊。因此,讓我們建立一個新的控制器來顯示該資訊,但僅在使用者登入時顯示。

右鍵單擊控制器資料夾,然後選擇“新增”→“控制器”。

User Logged in

選擇 MVC 5 控制器 - 空控制器,然後單擊“新增”。

輸入名稱 SecretController 並單擊“新增”按鈕。

SecretController

它將在內部包含兩個操作,如下面的程式碼所示。

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

當您執行此應用程式時,您可以訪問此資訊而無需任何身份驗證,如下面的螢幕截圖所示。

Secret Information Here

因此,只有經過身份驗證的使用者才能訪問 Secret 操作方法,而 PublicInfo 可以被任何人在沒有任何身份驗證的情況下使用。

要保護此特定操作並阻止未經身份驗證的使用者到達此處,您可以使用 Authorize 屬性。Authorize 屬性在沒有任何其他引數的情況下將確保知道使用者身份並且他們不是匿名使用者。

// GET: Secret
[Authorize]
public ContentResult Secret(){
   return Content("Secret informations here");
}

現在再次執行此應用程式並指定相同的 URL https://:54232/Secret/Secret。MVC 應用程式將檢測到您無權訪問應用程式的該特定區域,並且它會自動將您重定向到登入頁面,在該頁面上它將為您提供登入並嘗試返回到您被拒絕訪問的應用程式區域的機會。

Redirect Automatically Login Page

您可以看到它在返回 URL 中指定,這實際上告訴此頁面,如果使用者成功登入,則將其重定向回 /secret/secret。

輸入您的憑據並單擊“登入”按鈕。您將看到它直接轉到該頁面。

Secret Information Here

如果您返回主頁並登出,則無法訪問秘密頁面。系統將再次要求您登入,但如果您轉到 /Secret/PublicInfo,即使您未經身份驗證,您也可以看到該頁面。

Public Information Here

因此,當您不想在控制器內部的每個操作上都放置授權時,在控制器內部幾乎所有內容都需要授權。在這種情況下,您始終可以將此過濾器應用於控制器本身,現在此控制器內的每個操作都將要求使用者經過身份驗證。

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");
      }
   }
}

執行此應用程式,您可以在不登入的情況下訪問 /Secret/PublicInfo,但其他操作將需要身份驗證。

Public Information Here

它將僅允許匿名使用者訪問此一個操作。

使用Authorize屬性,您還可以指定一些引數,例如允許某些特定使用者訪問此操作。

using System.Web.Mvc;

namespace MVCSecurityDemo.Controllers{
   [Authorize(Users = "ali.khan@outlook.com")]
   public class SecretController : Controller{
      // GET: Secret
      public ContentResult Secret(){
         return Content("Secret informations here");
      }
		
      [AllowAnonymous]
      public ContentResult PublicInfo(){
         return Content("Public informations here");
      }
   }
}

當您執行此應用程式並訪問/secret/secret時,它會要求您登入,因為您不是此控制器的正確使用者。

Go to Secret
廣告