ASP.NET MVC - 安全性

在本章中,我们将讨论如何在应用程序中实现安全功能.我们还将查看ASP.NET中包含的新成员资格功能,并可从ASP.NET MVC中使用.在最新版本的ASP.NET中,我们可以使用以下&minus来管理用户身份;

  • Cloud

  • SQL数据库

  • 本地Windows活动目录

在本章中,我们还将看一看在作为ASP.NET一部分的新身份组件中,了解如何为我们的用户和角色定制成员资格.

身份验证

身份验证用户意味着验证用户的身份.这非常重要.出于显而易见的原因,您可能只需要向经过身份验证的用户提供应用程序.

让我们创建一个新的ASP.Net MVC应用程序.

新MVC应用程序

单击"确定"继续.

当你开始一个新的ASP.NET应用程序,该过程的其中一个步骤是为应用程序需求配置身份验证服务.

选择MVC模板,您将看到现在已启用"更改身份验证"按钮./p> 启用身份验证按钮

这是通过"更改身份验证"按钮完成的出现在"新建项目"对话框中.默认身份验证是,个人用户帐户.

身份验证选项

单击"更改"按钮后,您将看到一个包含四个选项的对话框,其中如下.

无身份验证

第一个选项是"无身份验证",当您要构建不具有身份验证的网站时,将使用此选项关心访客是谁.

无认证

这是向所有人开放,每个人都像每一页一样连接.您可以随时更改,但"无身份验证"选项意味着不会有任何功能来识别访问该网站的用户.

个人用户帐户

第二个选项是个人用户帐户,这是用户可以访问网站的传统的基于表单的身份验证.他们可以注册,创建登录,默认情况下,他们的用户名使用一些新的ASP.NET身份功能存储在SQL Server数据库中,我们将查看这些功能.

个人用户帐户

密码也存储在数据库中,但首先进行哈希处理.由于密码是经过哈希处理的,因此您不必担心数据库中存在明文密码.

此选项通常用于要建立身份标识的Internet站点一个用户.除了让用户使用您网站的密码创建本地登录之外,您还可以启用来自Microsoft,Google,Facebook和Twitter等第三方的登录.

这允许用户使用他们的真实账户或他们的Twitter账户登录您的网站,他们可以选择本地用户名,但您不需要存储任何密码.

这是我们的选项我会花一些时间在这个模块中;单个用户帐户选项.

工作和学校帐户

第三个选项是使用组织帐户,这通常用于您的业务应用程序将使用活动目录联合服务.

工作学校帐户

您将设置Office 365或使用Azure Active Directory服务,并且您可以对内部应用程序和云应用程序进行单点登录.

您还需要提供应用程序ID因此,如果这是基于Azure的,您的应用程序将需要在Windows Azure管理门户中注册,并且应用程序ID将在可能已注册的所有应用程序中唯一标识此应用程序.

Windows身份验证

第四个选项是Windows身份验证,适用于Intranet应用程序.

W indows身份验证

用户登录到Windows桌面,可以启动浏览器到位于同一防火墙内的应用程序. ASP.NET可以自动获取用户的身份,即由Active Directory建立的身份.此选项不允许对站点进行任何匿名访问,但这又是一个可以更改的配置设置.

让我们看一下基于表单的身份验证,名称,个人用户帐户.此应用程序将在本地SQL Server数据库中存储用户名和密码,旧密码,并且在创建此项目时,Visual Studio还将添加NuGet包.

基于表单的身份验证

现在运行此应用程序,当您第一次访问此应用程序时,您将成为匿名用户.

匿名用户

您将无法登录帐户所以你需要在这个网站上注册.

点击注册链接,你会看到以下视图.

点击注册链接

输入您的电子邮件ID和密码.

输入EmailId密码

单击"注册".现在,应用程序将识别您.

点击注册

它将能够显示您的名字.在下面的屏幕截图中,您可以看到Hello,muhammad.waqas @ outlook.com!被展示.您可以单击它,它是指向您可以更改密码的页面的链接.

显示您的姓名

您还可以注销,关闭,重新启动,一周后返回,您应该能够使用之前使用的凭据登录.现在点击注销按钮,它将显示以下页面.

点击注销按钮

再次单击登录链接,您将转到以下页面.

点击登录链接

您可以使用相同的凭据再次登录.

现场背后有很多工作要做到这一点点.但是,我们要做的是检查每个功能并查看如何构建此UI.什么是管理注销和登录过程?这些信息在数据库中排序在哪里?

让我们从几个简单的基础开始.首先,我们将看到如何显示此用户名.从解决方案资源管理器中的View/Shared文件夹中打开_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>&copy; @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'

授权

我们假设我们有某种类型我们想要保护未经身份验证的用户的信息.因此,让我们创建一个新的控制器来显示该信息,但仅限于用户登录时.

右键单击控制器文件夹并选择Add → 控制器.

用户登录

选择一个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操作方法,并且任何人都可以使用PublicInfo而无需任何身份验证.

要保护此特定操作并防止未经身份验证的用户到达此处,您可以使用授权属性.没有任何其他参数的Authorize属性将确保用户的身份是已知的并且他们不是匿名用户.

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

现在再次运行此应用程序并指定相同的URL http://localhost:54232/Secret/Secret . MVC应用程序将检测到您无权访问该应用程序的特定区域,它会自动将您重定向到登录页面,在此页面上,您将有机会登录并尝试返回应用程序的该区域你被拒绝的地方.

重定向自动登录页面

你可以看到它在返回URL中指定,它实际上告诉该页面,如果用户成功登录,则将它们重定向回/secret/secret.

输入您的凭据并单击'登录'按钮.你会看到它直接进入那个页面.

秘密信息在这里

如果您返回主页并注销,则无法进入秘密页面.您将再次被要求登录,但如果转到/Secret/PublicInfo,您可以看到该页面,即使您未经过身份验证.

公开信息在这里

所以,当你在一个控制器里面几乎所有东西时都不希望对每一个动作都放置授权需要授权.在这种情况下,您始终可以将此过滤器应用于控制器本身,现在此控制器内的每个操作都需要对用户进行身份验证.

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但其他动作将需要身份验证.

公共信息在这里

它将允许匿名用户只进行这一操作.

使用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时,它会问你登录,因为它不是该控制器的正确用户.

转到秘密