七天学会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 CreateEmployeeViewModel3.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相关文章推荐
- 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理
- 七天学会ASP.NET MVC (四)——用户授权认证问题
- 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理
- ASP.NET MVC图片管理(删除)
- [漏洞分析] CTF:ASP源码审计认证绕过
- 如何设置ASP.NET页面的运行超时时间
- asp.net Ajax的应用
- OData v4 - Web API 轻量级应用(使用Entity Framwork)-Endpoint
- ASP.NET MVC图片管理(上传,预览与显示)
- asp.net mvc 如何在View中获取Url参数的值
- ASP.NET MVC显示HTML字符串
- ASP.NET中使用Razor语法(C#)怎样获取当前浏览器的cookie
- 让Windows Server 2008 + IIS 7+ ASP.NET 支持10万并发请求
- 用Jasper制作贷款分期报表
- Spring基于注解@AspectJ的AOP
- ASP.NET MVC随想录——创建自定义的Middleware中间件
- asp.net 学习之路之gridView控件之修改数据
- ASP.NET MVC 基于页面的权限管理
- ASP.Net Cache(缓存)
- ASP.Net MVC 使用MySQL 【转】