小編應各位的要求,快馬加鞭,馬不停蹄的終于:七天學會 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 (五)——Layout頁面使用和用戶角色管理
七天學會ASP.NET MVC (六)——線程問題、異常處理、自定義URL
目錄
實驗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字符長度不能大于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
關于實驗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>
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.js
- jQuery.valiadte.js
- jquery.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 驗證?
是,可手動添加屬性。
總結
這就是本節所講的用戶授權與客戶端驗證的實現,在第五天我們會講到更高級的應用,請持續關注,不要走開哦!
有了本節MVC關于用戶授權與客戶端驗證的講解,相信會對大家的MVC開發過程有所幫助。在使用MVC進行開發時,還可以利用一些開發工具。使用 ComponentOne Studio ASP.NET MVC 這款輕量級控件,在開發效率大大提高的同時,工作量也會大大減少。
原文鏈接 http://www.codeproject.com/Articles/996832/Learn-MVC-Project-in-Days-Day
相關閱讀:
文章列表