MVC Controllers和Forms验证
想想下,一組從Forms驗(yàn)證抽象出來的登入/登出Controllers行為特有的ActionResult實(shí)現(xiàn)。。
我已經(jīng)使用ASP.NETMVC重新實(shí)現(xiàn)了我的個(gè)人網(wǎng)站(projects.nikhilk.net)的一部分。其中之一就是登入/登出功能的實(shí)現(xiàn)。當(dāng)你創(chuàng)建一個(gè)新的ASP.NETMVC應(yīng)用程序,默認(rèn)的就會(huì)包含一個(gè)簡(jiǎn)單的AccountController。這個(gè)Controller中包含了登入/登出,并實(shí)現(xiàn)了IFormsAuthentication接口。其默認(rèn)實(shí)現(xiàn)基于System.Web.Security.FormsAuthentication APIs(SetAuthCookie and SignOut)。可以仿照給這個(gè)接口的實(shí)現(xiàn)以便用于United測(cè)試。
盡管如此,當(dāng)我在自己的Controller中實(shí)現(xiàn)登入/登出時(shí),我發(fā)現(xiàn)一個(gè)奇怪現(xiàn)象,行為(actions)直接的訪問FormsAuthentication(甚至是通過接口)。我以為行為應(yīng)該簡(jiǎn)單地完成用戶驗(yàn)證,而后返回一個(gè)處理生成響應(yīng)的匹配的ActionResult,這該實(shí)例中就是設(shè)置或清除cookie,并重定向Url。為此,我創(chuàng)建了FormsLoginResult和FormsLogoutResult。很明顯的他們是成對(duì)的出現(xiàn)的,but I thought I'd go ahead and share anyway。
首先,我將顯示AccountController中修改過的Login和Logout方法。
[AcceptVerbs(HttpVerbs.Post)] public ActionResult Login(string username, string password, bool rememberMe) {...if (ViewData.ModelState.IsValid) {// Attempt to loginbool loginSuccessful = Provider.ValidateUser(username, password);if (loginSuccessful) {return new FormsLoginResult(username, rememberMe);}else {...}}// If we got this far, something failed, redisplay form...return View(); }public ActionResult Logout() {return new FormsLogoutResult(); }現(xiàn)在Login和Logout行為不再和authentication是否通過cookie跟蹤以及需要重定位到哪里(默認(rèn)主頁、參數(shù)關(guān)聯(lián)的url等)相關(guān)聯(lián)。
其次、建立這兩個(gè)函數(shù)的測(cè)試單元。我使用Moq實(shí)現(xiàn)測(cè)試需要的MembershipProvider的模擬,當(dāng)是不再需要IFormsAuthentication的實(shí)現(xiàn)。
[TestClass] public class AccountControllerTest {[TestMethod]public void LoginSuccessful() {string testUserName = "TestUser";string testPassword = "TestPassword";Mock<MembershipProvider> mockMembership = new Mock<MembershipProvider>();mockMembership.Expect<bool>(m => m.ValidateUser(testUserName, testPassword)).Returns(true).AtMostOnce().Verifiable();AccountController controller = new AccountController(mockMembership.Object);ActionResult result = controller.Login(testUserName, testPassword, false);Assert.IsInstanceOfType(result, typeof(FormsLoginResult));FormsLoginResult loginResult = (FormsLoginResult)result;Assert.AreEqual<string>(loginResult.UserName, testUserName);Assert.AreEqual<bool>(loginResult.PersistentCookie, false);}[TestMethod]public void LoginFailure() {string testUserName = "TestUser";string testPassword = "TestPassword";Mock<MembershipProvider> mockMembership = new Mock<MembershipProvider>();mockMembership.Expect<bool>(m => m.ValidateUser(testUserName, testPassword)).Returns(true).AtMostOnce().Verifiable();AccountController controller = new AccountController(mockMembership.Object);ActionResult result = controller.Login(testUserName, "badPassword", false);Assert.IsInstanceOfType(result, typeof(ViewResult));} }下面是FormsLoginResult 和FormsLogoutResult的實(shí)現(xiàn)。這里使用了MVC提供的構(gòu)建自定義action results可擴(kuò)展性較好的實(shí)現(xiàn)。
public class FormsLoginResult : ActionResult {private string _userName;private string _userData;private bool _persistentCookie;public FormsLoginResult(string userName): this(userName, /* persistentCookie */ false) {}public FormsLoginResult(string userName, bool persistentCookie) {if (String.IsNullOrEmpty(userName)) {throw new ArgumentNullException("userName");}_userName = userName;_persistentCookie = persistentCookie;}public bool PersistentCookie {get { return _persistentCookie; }}public string UserData {get { return _userData; }set { _userData = value; }}public string UserName {get { return _userName; }}public override void ExecuteResult(ControllerContext context) {HttpResponseBase response = context.HttpContext.Response;if (String.IsNullOrEmpty(_userData)) {FormsAuthentication.SetAuthCookie(_userName, _persistentCookie);}else {FormsAuthenticationTicket ticket =new FormsAuthenticationTicket(1, _userName,DateTime.Now, DateTime.Now.AddMinutes(30),_persistentCookie,_userData, FormsAuthentication.FormsCookiePath);string encryptedTicket = FormsAuthentication.Encrypt(ticket);HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName,encryptedTicket);cookie.HttpOnly = true;cookie.Secure = FormsAuthentication.RequireSSL;cookie.Path = FormsAuthentication.FormsCookiePath;if (FormsAuthentication.CookieDomain != null) {cookie.Domain = FormsAuthentication.CookieDomain;}response.Cookies.Add(cookie);}response.Redirect(FormsAuthentication.GetRedirectUrl(_userName, _persistentCookie));} }令人慶幸的是,FormsLoginResult同樣的在FormsAuth cookie內(nèi)封裝了一些自定義用戶數(shù)據(jù),這些數(shù)據(jù)可以通過HttpApplication的Authenticate事件獲取,并可以使用FormsAuthentication.Decrypt將AuthCookie內(nèi)數(shù)據(jù)轉(zhuǎn)換為一個(gè)FormsAuthenticationTicket實(shí)例,以及從Ticket中獲取的用戶數(shù)據(jù)。我在我的網(wǎng)站中使用這個(gè)跟蹤一些元數(shù)據(jù)以便于在Requests后重新創(chuàng)建代理實(shí)例。
第二個(gè)action result FormsLogoutResult非常簡(jiǎn)單。
?
public class FormsLogoutResult : ActionResult {private string _url;public FormsLogoutResult(): this(FormsAuthentication.DefaultUrl) {}public FormsLogoutResult(string url) {if (String.IsNullOrEmpty(url)) {throw new ArgumentNullException("url");}_url = url;}public string Url {get { return _url; }}public override void ExecuteResult(ControllerContext context) {FormsAuthentication.SignOut();context.HttpContext.Response.Redirect(_url);} }源:http://www.nikhilk.net/Default.aspx轉(zhuǎn)載于:https://www.cnblogs.com/Silicon-Fado/archive/2009/03/15/1412198.html
總結(jié)
以上是生活随笔為你收集整理的MVC Controllers和Forms验证的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS实现的展开隐藏效果
- 下一篇: c++的程序的文件结构