您的位置:首页 > 编程语言 > ASP

七天学会ASP.NET MVC (四)――用户授权认证问题

2015-07-07 14:42 901 查看
小编应各位的要求,快马加鞭,马不停蹄的终于:七天学会 Asp.Net MVC 第四篇出炉,在第四天的学习中,我们主要了学习如何在MVC中如何实现认证授权等问题,本节主要讲了验证错误时的错误值,客户端验证,授权认证及登录注销功能的实现。

系列文章

七天学会ASP.NET MVC (一)――深入理解ASP.NET MVC七天学会ASP.NET MVC (二)――ASP.NET MVC 数据传递七天学会ASP.NET MVC (三)――ASP.Net MVC 数据处理七天学会ASP.NET MVC (四)――用户授权认证问题七天学会ASP.NET MVC (五)――Layout页面使用和用户角色管理

目录

实验15 ――有关错误验证的保留值。实验16――添加客户端验证实验17――添加授权认证实验18――在View中显示用户名实验19――实现注销操作实验20――实现登录页面验证实验21――实现登录页面客户端验证总结

实验15――有关错误验证的保留值

在上一节的实验13,我们介绍了服务器端的身份验证,实验14中添加了客户端验证的支持,希望每位读者都能够把实验14理解透彻,逐行代码查看,保证每行代码都理解了,这样才有助于理解我们接下来的实验。实验15中将学习如何在验证失败时,填充值。1. 创建 CreateEmployeeViewModel 类。在ViewModel文件夹下,新建类:
public class CreateEmployeeViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Salary { get; set; }
}
2. 修改 SaveEmployee 方法为了重新生成,重用Model Binder创建的 Employee 对象,修改 SaveEmployee 方法。
1:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
2:  {
3:      switch (BtnSubmit)
4:      {
5:          case "Save Employee":
6:              if (ModelState.IsValid)
7:              {
8:                  EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
9:                  empBal.SaveEmployee(e);
10:                  return RedirectToAction("Index");
11:              }
12:              else
13:              {
14:                  CreateEmployeeViewModel vm = new CreateEmployeeViewModel();
15:                  vm.FirstName = e.FirstName;
16:                  vm.LastName = e.LastName;
17:                  if (e.Salary.HasValue)
18:                  {
19:                      vm.Salary = e.Salary.ToString();
20:                  }
21:                  else
22:                  {
23:                      vm.Salary = ModelState["Salary"].Value.AttemptedValue;
24:                  }
25:                  return View("CreateEmployee", vm); // Day 4 Change - Passing e here
26:              }
27:          case "Cancel":
28:              return RedirectToAction("Index");
29:      }
30:      return new EmptyResult();
31:  }
3. 填充View的值3.1 将View设置为强类型的View在 CreateEmployee View文件开始添加以下代码:
1:  @using WebApplication1.ViewModels
2:  @model CreateEmployeeViewModel
3.2 在响应控件中显示Model值
1:  ...
2:
3:  ...
4:
5:  ...
6:
7:  <input type="text" id="TxtFName" name="FirstName" value="@Model.FirstName" />
8:
9:  ...
10:
11:  ...
12:
13:  ...
14:
15:  <input type="text" id="TxtLName" name="LastName" value="@Model.LastName" />
16:
17:  ...
18:
19:  ...
20:
21:  ...
22:
23:  <input type="text" id="TxtSalary" name="Salary" value="@Model.Salary" />
24:
25:  ...
26:
27:  ...
28:
29:  ...
4. 运行点击Add New链接浏览器提示错误。我们在实验讲述完之后,再来解释为什么会出现错误。5. 修改AddNew方法
1:  public ActionResult AddNew()
2:  {
3:      return View("CreateEmployee”, new CreateEmployeeViewModel());
4:  }
6. 运行测试测试1点击 “Add New”跳转到 AddNew 页面。设置名字为空输入工资值 56点击“Save Employee”按钮。会出现验证失败,但是数字 56 仍然显示在 Salary 文本框中。测试2如图所示,姓名仍然保留在文本框中,却未保留工资,接下来我们来讨论上述问题的解决办法。

关于实验15

是否是真的将值保留?不是,是从post数据中重新获取的。为什么需要在初始化请求时,在Add New 方法中传递 new CreateEmployeeViewModel()?View中,试着将Model中的数据重新显示在文本框中。如:
<input id="TxtSalary" name="Salary" type="text" value="@Model.Salary" />
如上所示,可以访问当前Model的“First Name”属性,如果Model 为空,会抛出类无法实例化的异常“Object reference not set to an instance of the class”。当点击”Add New“超链接时,请求会通过Add New方法处理,在该Action 方法中,可以不传递任何数据。即就是,View中的Model属性为空。因此会抛出“Object reference not set to an instance of the class”异常。为了解决此问题,所以会在初始化请求时,传”new CreateEmployeeViewModel()“。上述的这些功能,有什么方法可以自动生成?使用HTML 帮助类就可以实现。在实验16中我们会讲解HTML 帮助类。

实验16――添加客户端验证

首先了解,需要验证什么?1. FirstName 不能为空2. LastName字符长度不能大于53. Salary不能为空,且应该为数字类型4. FirstName 不能包含@字符接下来,实现客户端验证功能1. 创建JavaScript 验证文件在Script文件下,新建JavaScript文件,命名为“Validations.js”2. 创建验证函数在“Validations.js”文件中创建验证函数:
1:  function IsFirstNameEmpty() {
2:      if (document.getElementById('TxtFName').value == "") {
3:          return 'First Name should not be empty';
4:      }
5:      else { return ""; }
6:  }
7:
8:  function IsFirstNameInValid() {
9:      if (document.getElementById('TxtFName').value.indexOf("@") != -1) {
10:          return 'First Name should not contain @';
11:      }
12:      else { return ""; }
13:  }
14:  function IsLastNameInValid() {
15:      if (document.getElementById('TxtLName').value.length>=5) {
16:          return 'Last Name should not contain more than 5 character';
17:      }
18:      else { return ""; }
19:  }
20:  function IsSalaryEmpty() {
21:      if (document.getElementById('TxtSalary').value=="") {
22:          return 'Salary should not be empty';
23:      }
24:      else { return ""; }
25:  }
26:  function IsSalaryInValid() {
27:      if (isNaN(document.getElementById('TxtSalary').value)) {
28:          return 'Enter valid salary';
29:      }
30:      else { return ""; }
31:  }
32:  function IsValid() {
33:
34:      var FirstNameEmptyMessage = IsFirstNameEmpty();
35:      var FirstNameInValidMessage = IsFirstNameInValid();
36:      var LastNameInValidMessage = IsLastNameInValid();
37:      var SalaryEmptyMessage = IsSalaryEmpty();
38:      var SalaryInvalidMessage = IsSalaryInValid();
39:
40:      var FinalErrorMessage = "Errors:";
41:      if (FirstNameEmptyMessage != "")
42:          FinalErrorMessage += "\n" + FirstNameEmptyMessage;
43:      if (FirstNameInValidMessage != "")
44:          FinalErrorMessage += "\n" + FirstNameInValidMessage;
45:      if (LastNameInValidMessage != "")
46:          FinalErrorMessage += "\n" + LastNameInValidMessage;
47:      if (SalaryEmptyMessage != "")
48:          FinalErrorMessage += "\n" + SalaryEmptyMessage;
49:      if (SalaryInvalidMessage != "")
50:          FinalErrorMessage += "\n" + SalaryInvalidMessage;
51:
52:      if (FinalErrorMessage != "Errors:") {
53:          alert(FinalErrorMessage);
54:          return false;
55:      }
56:      else {
57:          return true;
58:      }
59:  }
3. 在 “CreateEmployee”View 中添加 Validations.js文件引用:
1:  <script src="~/Scripts/Validations.js"></script>
4. 在点击 SaveEmployee按钮时,调用验证函数,如下:
<input type="submit" name="BtnSubmit" value="Save Employee" onclick="IsValid();"/>
5.  运行测试点击 Add New 链接,跳转到 ”Add  New“页面测试1测试2

关于实验16

为什么在点击”SaveEmployee “按钮时,需要返回关键字?如之前实验9讨论的,当点击提交按钮时,是给服务器发送请求,验证失败时对服务器请求没有意义。通过添加”return false“代码,可以取消默认的服务器请求。在 IsValid函数将返回false,表示验证失败来实现预期的功能。除了提示用户,是否可以在当前页面显示错误信息?是可以得,只需要为每个错误创建span 标签,默认设置为不可见,当提交按钮点击时,如果验证失败,使用JavaScript修改错误的可见性。自动获取客户端验证还有什么方法?是,当使用Html 帮助类,可根据服务端验证来获取自动客户端验证,在以后会详细讨论。服务器端验证还有没有必须使用?在一些JavaScript脚本代码无法使用时,服务器端可以替代使用。

实验 17 添加授权认证

在实验17中,会改进GetView方法,使其变得更加安全,只有合法的用户才能够访问该方法。在本系列的第一讲中,我们了解了Asp.Net和MVC的意义,知道MVC是Asp.net的一部分,MVC继承了ASP.NET的所有特征,包含表单认证。先来了解ASP.NET是如何进行Form认证的。终端用户在浏览器的帮助下,发送Form认证请求。浏览器会发送存储在客户端的所有相关的用户数据。当服务器端接收到请求时,服务器会检测请求,查看是否存在 “Authentication Cookie”的Cookie。如果查找到认证Cookie,服务器会识别用户,验证用户是否合法。如果为找到“Authentication Cookie”,服务器会将用户作为匿名(未认证)用户处理,在这种情况下,如果请求的资源标记着 protected/secured,用户将会重定位到登录页面。1. 创建 AuthenticationController Login 行为方法右击controller文件夹,选择添加新Controller,新建并命名为”Authentication“即Controller的全称为”AuthenticationController“。新建Login action方法:
1:  public class AuthenticationController : Controller
2:  {
3:      // GET: Authentication
4:      public ActionResult Login()
5:      {
6:          return View();
7:      }
8:  }
2. 创建Model在Model 文件夹下新建Model,命名为 UserDetails。
1:  namespace WebApplication1.Models
2:  {
3:      public class UserDetails
4:      {
5:          public string UserName { get; set; }
6:          public string Password { get; set; }
7:      }
8:  }
3. 创建Login View在“~/Views/Authentication”文件夹下,新建View命名为Login,并将UserDetails转换为强View类型。在View中添加以下代码:
1:  @model WebApplication1.Models.UserDetails
2:
3:  @{
4:
5:      Layout = null;
6:
7:  }
8:
9:  <!DOCTYPE html>
10:
11:  <html>
12:
13:  <head>
14:
15:      <meta name="viewport" content="width=device-width" />
16:
17:      <title>Login</title>
18:
19:  </head>
20:
21:  <body>
22:
23:      <div>
24:
25:          @using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))
26:
27:          {
28:
29:              @Html.LabelFor(c=>c.UserName)
30:
31:              @Html.TextBoxFor(x=>x.UserName)
32:
33:
34:
35:              <br />
36:
37:              @Html.LabelFor(c => c.Password)
38:
39:              @Html.PasswordFor(x => x.Password)
40:
41:              <br />
42:
43:
44:              <input type="submit" name="BtnSubmit" value="Login" />
45:
46:          }
47:
48:      </div>
49:
50:  </body>
51:
52:  </html>
在上述代码中可以看出,使用HtmlHelper类在View中替代了纯HTML代码。View中可使用”Html”调用HtmlHelper类HtmlHelper类函数返回html字符串示例1:
1:  @Html.TextBoxFor(x=>x.UserName)
转换为HTML代码
<input id="UserName" name="UserName" type="text" value="" />
示例2:
1:  @using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))
2:  {
3:  }
转换为HTML代码:
1:  <form action="/Authentication/DoLogin" method="post">
2:  </form>
4. 运行测试输入Login action方法的URL:“http://localhost:8870/Authentication/Login”5. 实现Form认证打开 Web.config文件,在System.Web部分,找到Authentication的子标签。如果不存在此标签,就在文件中添加Authentication标签。设置Authentication的Mode为Forms,loginurl设置为”Login”方法的URL.
1:  <authentication mode="Forms">
2:  <forms loginurl="~/Authentication/Login"></forms>
3:  </authentication>
6. 让Action 方法更安全在Index action 方法中添加认证属性 [Authorize].
1:  [Authorize]
2:  public ActionResult Index()
3:  {
4:      EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
5:  ......
7. 运行测试,输入 EmployeeController 的 Index action的URL:“http://localhost:8870/Employee/Index”对于Index action的请求会自动重链接到 login action。8. 创建业务层功能打开 EmployeeBusinessLayer 类,新建 IsValidUser方法:
1:  public bool IsValidUser(UserDetails u)
2:  {
3:      if (u.UserName == "Admin" && u.Password == "Admin")
4:      {
5:          return true;
6:      }
7:      else
8:      {
9:          return false;
10:      }
11:  }
9. 创建 DoLogin action 方法打开 AuthenticationController 类,新建action 方法命名为 DoLogin。当点击登录时,Dologin action 方法会被调用。Dologin 方法的功能:通过调用业务层功能检测用户是否合法。如果是合法用户,创建认证Cookie。可用于以后的认证请求过程中。如果是非法用户,给当前的ModelState添加新的错误信息,将错误信息显示在View中。
1:  [HttpPost]
2:  public ActionResult DoLogin(UserDetails u)
3:  {
4:      EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
5:      if (bal.IsValidUser(u))
6:      {
7:          FormsAuthentication.SetAuthCookie(u.UserName, false);
8:          return RedirectToAction("Index", "Employee");
9:      }
10:      else
11:      {
12:          ModelState.AddModelError("CredentialError", "Invalid Username or Password");
13:          return View("Login");
14:      }
15:  }
10.在View 中显示信息打开Login View,在 @Html.BeginForm中 添加以下代码
1:  @Html.ValidationMessage("CredentialError", new {style="color:red;" })
2:  @using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))
3:  {
11. 运行测试测试1测试2

关于实验17

为什么Dologin会添加 HttpPost 属性,还有其他类似的属性吗?该属性可使得DoLogin 方法打开Post 请求。如果有人尝试获取DoLogin,将不会起作用。还有很多类似的属性如HttpGet,HttpPut和HttpDelete属性.FormsAuthentication.SetAuthCookie是必须写的吗?是必须写的。让我们了解一些小的工作细节。客户端通过浏览器给服务器发送请求。当通过浏览器生成,所有相关的Cookies也会随着请求一起发送。服务器接收请求后,准备响应。请求和响应都是通过HTTP协议传输的,HTTP是无状态协议。每个请求都是新请求,因此当同一客户端发出二次请求时,服务器无法识别,为了解决此问题,服务器会在准备好的请求包中添加一个Cookie,然后返回。当客户端的浏览器接收到带有Cookie的响应,会在客户端创建Cookies。如果客户端再次给服务器发送请求,服务器就会识别。FormsAuthentication.SetAuthCookie将添加 “Authentication”特殊的Cookie来响应。是否意味着没有Cookies,FormsAuthentication 将不会有作用?不是的,可以使用URI代替Cookie。打开Web.Config文件,修改Authentication/Forms部分:
1:  <forms cookieless="UseUri" loginurl="~/Authentication/Login"></forms>
授权的Cookie会使用URL传递。通常情况下,Cookieless属性会被设置为“AutoDetect“,表示认证工作是通过Cookie完成的,是不支持URL传递的。FormsAuthentication.SetAuthCookie中第二个参数”false“表示什么?false决定了是否创建永久有用的Cookie。临时Cookie会在浏览器关闭时自动删除,永久Cookie不会被删除。可通过浏览器设置或是编写代码手动删除。当凭证错误时,UserName 文本框的值是如何被重置的?HTML 帮助类会从Post 数据中获取相关值并重置文本框的值。这是使用HTML 帮助类的一大优势。Authorize属性有什么用?Asp.net MVC中提供四种过滤器来过滤请求和响应的,Authorize属性是在Authorize过滤器之后执行的,可以确保授权请求Action 方法处理。需要为每个Action 方法添加授权属性吗?不需要,可以将授权属性添加到Controller 层或 Global 层。

实验18――在View中显示UserName

在本实验中,我们会在View中显示已登录的用户名1. 在ViewModel 中添加 UserName打开 EmployeeListViewModel,添加属性叫:UserName。
1:  public class EmployeeListViewModel
2:  {
3:      public List<EmployeeViewModel><employeeviewmodel> Employees { get; set; }
4:      public string UserName { get; set; }
5:  }
6:  </employeeviewmodel>
2. 给 ViewModel UserName 设置值修改 EmployeeController,修改 Index 方法。
1:  public ActionResult Index()
2:  {
3:      EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
4:      employeeListViewModel.UserName = User.Identity.Name; //New Line
5:  ......
3. 显示 View UserName
1:  <body>
2:
3:    <div style="text-align:right"> Hello, @Model.UserName </div>
4:
5:    <hr />
6:
7:    <a  href="/Employee/AddNew">Add New</a>
8:
9:      <div>
10:
11:         <table border="1"><span style="font-size: 9pt;">
12:  </span>
4. 运行

实验 19――实现注销功能

1. 创建注销链接,打开Index.cshtml 创建 Logout 链接如下:
1:  <body>
2:
3:      <div style="text-align:right">Hello, @Model.UserName
4:
5:      <a href="/Authentication/Logout">Logout</a></div>
6:
7:      <hr />
8:
9:      <a  href="/Employee/AddNew">Add New</a>
10:
11:      <div>
12:
13:          <table border="1">
2. 创建Logout Action 方法打开 AuthenticationController 添加新的Logout action方法:
1:  public ActionResult Logout()
2:  {
3:      FormsAuthentication.SignOut();
4:      return RedirectToAction("Login");
5:  }
3. 运行

实验20――实现登录页面验证

1. 添加 data annotation打开 UserDetails.cs,添加 Data Annotation:
1:  public class UserDetails
2:  {
3:
4:  [StringLength(7,MinimumLength=2, ErrorMessage = "UserName length should be between 2 and 7")]
5:      public string UserName { get; set; }
6:      public string Password { get; set; }
7:  }
2. 在View 中显示错误信息修改 Login.cshtml能够提示错误信息。
1:  @using (Html.BeginForm("DoLogin", "Authentication", FormMethod.Post))
2:  {
3:      @Html.LabelFor(c=>c.UserName)
4:      @Html.TextBoxFor(x=>x.UserName)
5:      @Html.ValidationMessageFor(x=>x.UserName)
6:  ......
3. 修改 DoLogin修改 DoLogin action 方法:
1:  [HttpPost]
2:  public ActionResult DoLogin(UserDetails u)
3:  {
4:      if (ModelState.IsValid)
5:      {
6:          EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
7:          if (bal.IsValidUser(u))
8:          {
9:              FormsAuthentication.SetAuthCookie(u.UserName, false);
10:              return RedirectToAction("Index", "Employee");
11:          }
12:          else
13:          {
14:              ModelState.AddModelError("CredentialError", "Invalid Username or Password");
15:              return View("Login");
16:          }
17:      }
18:      else
19:      {
20:          return View("Login");
21:      }
22:  }
4. 运行

实验 21――登录页面实现客户端验证

在本实验中介绍一种方法实现客户端验证1. 下载 jQuery unobtrusive Validation文件右击项目,选择“Manage Nuget packages”,点击在线查找”jQuery Unobtrusive“,安装”Microsoft jQuery Unobtrusive Valiadtion“2. 在View 中添加 jQuery Validation 引用在Scripts文件中,添加以下 JavaScript文件jQuery-Someversion.jsjQuery.valiadte.jsjquery.validate.unobtrusive打开 Login.cshtml,在文件顶部包含这三个js文件:
1:  <script src="~/Scripts/jquery-1.8.0.js"></script>
2:  <script src="~/Scripts/jquery.validate.js"></script>
3:  <script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
3. 运行

关于实验21

客户端验证是如何实现的?如上所述,客户端验证并不是很麻烦,在Login View中,HTML元素能够使用帮助类来生成,Helper 函数能够根据Data Annotation属性的使用生成带有属性的HTML 标记元素。例如:
1:  @Html.TextBoxFor(x=>x.UserName)
2:  @Html.ValidationMessageFor(x=>x.UserName)
根据以上代码生成的HTML 代码如下:
1:  <input data-val="true" data-val-length="UserName length should be between 2 and 7" data-val-length-max="7" data-val-length-min="2" id="UserName" name="UserName" type="text" value="" />
2:  <span class="field-validation-error" data-valmsg-for="UserName" data-valmsg-replace="true"> </span>
jQuery Unobtrusive验证文件会使用这些自定义的HTML 属性,验证会在客户端自动生成。自动进行客户端验证是使用HTML 帮助类的又一大好处。是否可以使用不带HTML 帮助类的JavaScript 验证?是,可手动添加属性。

总结

这就是本节所讲的用户授权与客户端验证的实现,在第五天我们会讲到更高级的应用,请持续关注,不要走开哦!原文链接 http://www.codeproject.com/Articles/996832/Learn-MVC-Project-in-Days-Day本文出自 “葡萄城控件技术团队博客” 博客,请务必保留此出处http://powertoolsteam.blog.51cto.com/2369428/1671676
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: