ASP.Net MVC安全

在本章中,我們將討論如何在應用程序中實現安全功能。還將看到ASP.NET中包含的新成員特性,並可從ASP.NET MVC中使用。在ASP.NET的最新版本中,可以通過以下方式管理用戶身份 -

  • SQL數據庫
  • 本地Windows活動目錄

在本章中,我們將介紹作爲ASP.NET一部分的新身份組件,並瞭解如何自定義用戶和角色的成員資格。

認證

用戶的認證意味着驗證用戶的身份,這真的很重要。可能需要將您的應用程序僅顯示給經過身份驗證的用戶,原因很明顯。
我們來創建一個新的ASP.Net MVC應用程序項目:MVCSecurity 。點擊確定 繼續。
ASP.Net

當啓動一個新的ASP.NET應用程序時,這個過程中的一個步驟就是爲應用程序需要配置身份驗證服務。選擇MVC模板,將看到現在啓用了更改認證按鈕。
ASP.Net

這是通過出現在「新建項目」對話框中的「更改認證」按鈕完成的。默認身份驗證是個人用戶帳戶。

認證選項

當單擊更改按鈕時,您將看到一個對話框,其中包含四個選項,如下所示。

1. 不進行身份驗證

第一個選項是不驗證,當想建立一個不關心訪問者是誰的網站時使用這個選項。

它是開放給任何人和每個人連接爲每一個頁面。以後可以隨時更改,但「不進行身份驗證」 選項意味着不會有任何功能來識別訪問該網站的用戶。
ASP.Net

2. 個人用戶帳戶

第二個選項是個人用戶帳戶,這是用戶可以訪問網站的傳統的基於表單的身份驗證。 他們可以註冊,創建一個登錄名,默認情況下,用戶名是使用一些新的ASP.NET身份特性存儲在SQL Server數據庫中。
ASP.Net

密碼也存儲在數據庫中,但首先被散列。由於密碼是散列的,因此不必擔心在數據庫中的純文本密碼而被別人知道。

此選項通常用於要建立用戶身份的Internet站點。 除了允許用戶使用網站的密碼創建本地登錄外,還可以啓用來自Microsoft,Google,Facebook和Twitter等第三方的登錄。

這允許用戶使用他們的真實帳戶或他們的Twitter帳戶登錄到您的網站,但是您不需要存儲任何密碼。

這將在這個模塊中花費一些時間的選項。個人用戶帳戶 選項。

3. 工作和學校帳戶

第三個選擇是使用組織帳戶,這通常用於使用活動目錄聯合服務的業務應用程序。
ASP.Net
將設置Office 365或使用Azure Active Directory服務,並且您有內部應用程序和雲應用程序的單一登錄。

您還需要提供應用程序ID,以便應用程序需要在Windows Azure管理門戶(如果這是基於Azure的)上進行註冊,並且應用程序ID將在所有可能註冊的應用程序中唯一標識此應用程序。

4. Windows身份驗證

第四個選項是Windows身份驗證 ,適用於Intranet應用程序。
ASP.Net
用戶登錄到Windows桌面,並可以將瀏覽器啓動到位於同一防火牆內的應用程序。 ASP.NET可以自動獲取用戶的身份,即由活動目錄建立的身份。 該選項不允許任何匿名訪問該站點,但這也是一個可以更改的配置設置。

下面我們來看看基於表單的身份驗證 ,即名稱爲個人用戶帳戶的身份驗證。 此應用程序將用戶名和密碼,舊密碼存儲在本地SQL Server數據庫中,創建此項目時,Visual Studio也將添加NuGet包。

ASP.Net

現在運行這個應用程序,當您第一次訪問這個應用程序,那麼是以一個匿名用戶來訪問的。
ASP.Net

因爲您還沒有登錄的賬戶,所以需要在這個網站上先註冊一個用戶。

點擊註冊 鏈接,會看到下面的視圖。
ASP.Net

輸入您的電子郵件ID和密碼,例如:[[email protected]](mailto:[email protected])Abc[@123](https://github.com/123 "@123")

點擊註冊。 現在,應用程序將使用此賬戶信息識別您。

它將能夠顯示用戶的名字。 在下面的截圖中,可以看到:「你好,[email protected]!」 。 可以點擊它鏈接到一個頁面,可以在這個頁面中更改密碼。
ASP.Net

也可以註銷,關閉,重新啓動,一個星期後回來,應該可以使用之前使用的憑據登錄。現在點擊註銷 按鈕,它將顯示以下頁面。再次點擊登錄鏈接進入下一頁。可以使用相同的憑據重新登錄。

很多工作都在幕後進行到現在。 但是,我們想要做的是檢查每個功能,看看這個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),如下面的截圖所示。

ASP.Net

假設只有經過身份驗證的用戶才能夠使用Secret動作方法,並且任何人都可以使用PublicInfo,而不需要任何身份驗證。

爲了保護這個特定的操作並保證未經身份驗證的用戶到達此處,可以使用Authorize屬性。 沒有任何其他參數的授權屬性將確保用戶的身份是已知的,他們不是一個匿名用戶。

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

現在再次運行這個應用程序,並指定相同的URL:http://localhost:57742/Secret/Secret。 MVC應用程序將檢測到您無權訪問應用程序的特定區域,並且會自動重定向到登錄頁面,在那裏登錄並嘗試返回訪問受限的應用程序的URL。

ASP.Net

可以看到它在返回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])),它會要求您登錄。