小编应各位的要求,马不停蹄,快马加鞭的终于:七天学会 Asp.Net MVC 第四篇出炉,在第四天的学习中,咱们主要了学习如何在MVC中如何实现认证受权等问题,本节主要讲了验证错误时的错误值,客户端验证,受权认证及登陆注销功能的实现。html
七天学会ASP.NET MVC (一)——深刻理解ASP.NET MVCjquery
七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递浏览器
七天学会ASP.NET MVC (三)——ASP.Net MVC 数据处理安全
七天学会ASP.NET MVC (四)——用户受权认证问题服务器
七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理cookie
实验15 ——有关错误验证的保留值。mvc
实验16——添加客户端验证less
实验17——添加受权认证函数
实验18——在View中显示用户名工具
实验19——实现注销操做
实验20——实现登陆页面验证
实验21——实现登陆页面客户端验证
总结
在上一节的实验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
会出现验证失败,可是数字 56 仍然显示在 Salary 文本框中。
测试2
如图所示,姓名仍然保留在文本框中,却未保留工资,接下来咱们来讨论上述问题的解决办法。
是不是真的将值保留?
不是,是从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 帮助类。
首先了解,须要验证什么?
1. FirstName 不能为空
2. LastName字符长度不能大于5
3. 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
为何在点击”SaveEmployee “按钮时,须要返回关键字?
如以前实验9讨论的,当点击提交按钮时,是给服务器发送请求,验证失败时对服务器请求没有意义。经过添加”return false“代码,能够取消默认的服务器请求。
在 IsValid函数将返回false,表示验证失败来实现预期的功能。
除了提示用户,是否能够在当前页面显示错误信息?
是能够得,只须要为每一个错误建立span 标签,默认设置为不可见,当提交按钮点击时,若是验证失败,使用JavaScript修改错误的可见性。
自动获取客户端验证还有什么方法?
是,当使用Html 帮助类,可根据服务端验证来获取自动客户端验证,在之后会详细讨论。
服务器端验证还有没有必须使用?
在一些JavaScript脚本代码没法使用时,服务器端能够替代使用。
在实验17中,会改进GetView方法,使其变得更加安全,只有合法的用户才可以访问该方法。
在本系列的第一讲中,咱们了解了Asp.Net和MVC的意义,知道MVC是Asp.net的一部分,MVC继承了ASP.NET的全部特征,包含表单认证。
先来了解ASP.NET是如何进行Form认证的。
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代码。
示例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 方法的功能:
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
为何Dologin会添加 HttpPost 属性,还有其余相似的属性吗?
该属性可以使得DoLogin 方法打开Post 请求。若是有人尝试获取DoLogin,将不会起做用。还有不少相似的属性如HttpGet,HttpPut和HttpDelete属性.
FormsAuthentication.SetAuthCookie是必须写的吗?
是必须写的。让咱们了解一些小的工做细节。
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 层。
在本实验中,咱们会在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. 运行
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. 运行
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. 运行
在本实验中介绍一种方法实现客户端验证
1. 下载 jQuery unobtrusive Validation文件
右击项目,选择“Manage Nuget packages”,点击在线查找”jQuery Unobtrusive“,安装”Microsoft jQuery Unobtrusive Valiadtion“
2. 在View 中添加 jQuery Validation 引用
在Scripts文件中,添加如下 JavaScript文件
打开 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. 运行
客户端验证是如何实现的?
如上所述,客户端验证并非很麻烦,在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 验证?
是,可手动添加属性。
有了本节MVC关于用户受权与客户端验证的讲解,相信会对你们的MVC开发过程有所帮助。在使用MVC进行开发时,还能够利用一些开发工具。使用 ComponentOne Studio ASP.NET MVC 这款轻量级控件,在开发效率大大提升的同时,工做量也会大大减小。
这就是本节所讲的用户受权与客户端验证的实现,在第五天咱们会讲到更高级的应用,请持续关注,不要走开哦!
原文连接 http://www.codeproject.com/Articles/996832/Learn-MVC-Project-in-Days-Day