ASP.Net MVC安全
在本章中,我們將討論如何在應用程序中實現安全功能。還將看到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和密碼,例如:[[email protected]](mailto:[email protected])
和Abc[@123](https://github.com/123 "@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]](mailto:[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]](mailto:[email protected])
),它會要求您登錄。