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]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]),它會要求您登入。