ASP.NET MVC 登录验证
?好久沒寫隨筆了,這段時(shí)間沒 什么事情,領(lǐng)導(dǎo) 一直沒安排任務(wù),索性 一直在研究代碼,說實(shí)在的,這個(gè)登錄都 搞得我云里霧里的,所以這次我可能也講得不是 特別清楚,但是 我盡力把我知道的講出來,順便也對(duì)自己最近的工作 做義工總結(jié)吧。
我們的項(xiàng)目用到的一些 技術(shù)也跟大家提一下,主要是用了NHibernate,StructureMap,FluentHibernate等等,可能這篇文章我不會(huì) 全部 提到 ,不過相信后面,如果我要寫文章的話,肯定是會(huì)提到的。我自己也模仿 了公司的框架做了一個(gè) 簡(jiǎn)單的登錄(未完成)的,因?yàn)楦杏X公司的東西實(shí)在是很復(fù)雜,所以不一定可以完全消化,所以才 寫了一上午沒寫完 = =
首先,登錄的話,我是寫在一個(gè)Area里面,至于 怎么建立Area(區(qū)域)我就 不多累贅了,Area的名字我就 取成MS2Auth,因?yàn)?自己 喜歡MapleStory這個(gè)游戲,所以取了 它的 一個(gè)縮寫 單詞,以下是結(jié)構(gòu)。
我們新建一個(gè)Controller名叫AccountController這個(gè)就是我們 登錄用的主的控制器,然后再往Controller里面添加一些Action,比如我們添加一個(gè)LogOn的Action,代碼如下:
/// <summary>/// 登錄/// </summary>/// <param name="message"></param>/// <returns></returns>public ActionResult LogOn(MS2UserCheckTransferMsg message){if (message.IsLogin){return Json(new { Data=ShowpopupReminder(message)},JsonRequestBehavior.AllowGet);}if (string.IsNullOrEmpty(message.Email)){ViewBag.ShowpopupReminder = ShowpopupReminder(message);ViewBag.UserEmail = message.Email;}var logOnModel = new LogOnModel();if (Request.QueryString["GUID"] == "0"){TempData["errorMessage"] = ErrorMessage;}else if (Request.QueryString["Reason"] == "NoCookie"){TempData["errorMessage"] = NoCookieErrMessage;}if (User.Identity.IsAuthenticated){return Redirect("~/LogOff.aspx");}else{return View(logOnModel);}}大家 可能會(huì)先去關(guān)心MS2UserCheckTransferMsg這個(gè)類里面的東西。
/// <summary>/// 登陸檢查/// </summary>public class MS2UserCheckTransferMsg:IMessage{public string Email { get; set; }public string password { get; set; }public bool IsLogin { get; set; }}一個(gè) 是Email,一個(gè) 是密碼,另一個(gè) 就是“是否登錄”,是否登錄 是檢測(cè) 如果你訪問到了這個(gè)ACTION的話,如果你 已經(jīng)處于登錄狀態(tài)了,那么就會(huì)執(zhí)行下面的流程。
這里面的一個(gè) 重點(diǎn)是 “反射”,通過反射 去獲取某個(gè)類底下的方法。這個(gè)話 怎么 去理解 呢?首先大家主營(yíng)到 下面的一個(gè) 方法。
private bool ShowpopupReminder(MS2UserCheckTransferMsg message){var queryBus = ObjectFactory.GetInstance<IQueryBus>();return queryBus.Query<MS2UserCheckTransferMsg, dynamic>(message);}這里我們 通過 一個(gè) 工廠 方法去 得到IQueryBus的 一個(gè) 實(shí)例,然后 再用 這個(gè)實(shí)例反過來,去執(zhí)行一個(gè) Query的方法。
namespace YLW.MS2.Common.TransferMsg {public interface IQueryBus{TResponse Query<TRequest, TResponse>(TRequest message) where TResponse : class;} }那么 ,這個(gè)IQueryBus其實(shí)是 一個(gè) 接口,我需要 得到這個(gè)接口的一個(gè)實(shí)例,該怎么 辦呢?下面就提供了一種解決方法,大家想起來那個(gè)Global.asax文件了嗎,那個(gè)不是 進(jìn)行初始化的一個(gè)文件嗎?對(duì)的,就是 這么一個(gè)文件,我們 需要 做的,就是 在Application_Start里面進(jìn)行初始化,把這些 實(shí)例先一股腦的丟進(jìn)去,進(jìn)行工廠化處理,然后要的時(shí)候只要 指定實(shí)例名或者 類型的話,就可以 方便的取出來。
為此我們需要用到一個(gè)東西。那 就是StructureMap的For方法,來 注冊(cè)這個(gè)接口的實(shí)例。
public static void Init(){ObjectFactory.Configure(x =>x.For<IQueryBus>().Use<LocalQueryBus>(););}
當(dāng)然 ,這只是一個(gè)例子而已,具體的你 如果想注冊(cè)其他的東西的話,也可以 用類似的方法去 寫,大家 注意到 了沒有 ,有 一個(gè) 叫做IMessage的接口,這個(gè)接口里面不 包含 任何東西,我的理解就是 這個(gè)接口的作用只是作為一個(gè) 中轉(zhuǎn)而用的,另 一個(gè)接口 叫做IMessageHandler,這個(gè) 接口的話里面只有一個(gè)Execute方法。也就是下面要提到的,IMESSAGE只是 作為一個(gè)轉(zhuǎn)換而已 ,也就是 說 任何 實(shí)現(xiàn)了IMessage接口的類,不需要實(shí)現(xiàn)任何多余的方法,也就是說,這個(gè)只是依賴注入的一個(gè)中轉(zhuǎn)站而已(我個(gè)人的理解)。
下面的方法就是通過反射區(qū)調(diào)用Execute方法,而這個(gè)Execuute方法真正 所在的類,其實(shí)是被IMessageHanlder所 實(shí)現(xiàn)的接口的一個(gè) 方法。
public class LocalQueryBus:IQueryBus{public TResponse Query<TRequest, TResponse>(TRequest message) where TResponse : class{return (TResponse)QueryHandlerExecute((IMessage)message);}private object QueryHandlerExecute(IMessage message){var handlerType = typeof(IMessageHandler<>);var genericType = handlerType.MakeGenericType(message.GetType());var messageHandler = ObjectFactory.GetInstance(genericType);return messageHandler.GetType().GetMethod("Execute").Invoke(messageHandler, new object[] { message });}}?
下面 就說明了真正執(zhí)行的方法的實(shí)際位置:
public class MS2UserCheckHandler: IMessageHandler<MS2UserCheckMessage>總之我感覺 這種 反射 跳來跳去的,我頭都有點(diǎn) 花了,其中具體的用法具體去 考慮,比如 那個(gè) MakeGenericType,大家可以自己 去 查查 用法 。
由于有些 登錄的機(jī)制特別的復(fù)雜,比如有你需要 一個(gè)“公共秘鑰”去登錄 ,就是說你 需要 返回 一個(gè)公共密碼到另一臺(tái)服務(wù)器上面 去,只有你的用戶名和密碼以及那個(gè)公共秘鑰都對(duì)了,你才能登錄,這個(gè)有點(diǎn) 類似于支付寶的數(shù)字證書吧,雖然 沒 那么 復(fù)雜。那么,我們總不可能每次都去 匹配吧?這里告訴 大家 一個(gè)簡(jiǎn)單的方法,看下面的代碼。
#if DEBUGpublic ActionResult LogMeIn(LogOnModel model){return RedirectToAction("Landing");} #endif大家只要 用#if DEBUG #endif 代碼段,就可以調(diào)試本地的了,如果是服務(wù)器上的話,就不會(huì)執(zhí)行本段代碼 ,這段 代碼只是在 本地啟動(dòng)的時(shí)候才有用哦。下面告訴 大家 一種偽造 登錄的方法:可以使用Request.Headers.Add()方法去添加相應(yīng)的鍵值對(duì),比如 你 可以 往這里面 添加 用戶名,EMAIL,公共秘鑰ID等,如下面的代碼 所示。
Request.Headers.Add("SM_USER", user);Request.Headers.Add("EMAIL", email);然后 進(jìn)行本地調(diào)試的時(shí)候,只要把這些值取出來就行了,當(dāng)然了,我這么做 也許有些人會(huì)說沒意義,我的目的只是 為了模擬登錄的流程而已,僅此而已。
當(dāng)然 ,你需要一個(gè)判斷的過程,于是就有 了下面的方法:
public CommandResponse Command<TRequest>(TRequest message){var result = QueryHandlerExecute((IMessage)message);if (result!= null){return (CommandResponse) result;}return new CommandResponse();}具體的我也說不清楚,這里面感覺 還是 有點(diǎn) 復(fù)雜。。。
public class CommandResponse{public bool Success { get; set; }public string Message { get; set; }}
如果Success=true的話,那么就 使用下面這句話,這句話的作用就是使你的User.Identity.IsAuthenticated為True,表示 你已經(jīng)通過了登錄 驗(yàn)證。
FormsAuthentication.SetAuthCookie(model.MS2User, false);如果 你 沒有通過驗(yàn)證的話,那么 還需要 往TempData里面去放一些值,跳轉(zhuǎn)帶到新頁(yè)面 ,為什么 使用 TempData,因?yàn)榈卿浐?#xff0c;錯(cuò)誤 信息只顯示一次 ,所以用TempData,當(dāng)然如果 你是正常 退出的話,那么就 可以 這樣 。
System.Web.HttpContext.Current.Session.RemoveAll();FormsAuthentication.SignOut();return RedirectToAction("LogOn", "Account", new{area = "MS2Auth"});注意 在 這里 area是必須的,因?yàn)?我們把登錄的接口 放到了Area里面。好久沒寫了,文字比較拙劣,今天試著做了下登錄,沒 完全做出來,希望以后能有 進(jìn)一步的提高吧。
PS:差點(diǎn) 忘了貼登錄的View頁(yè)面,比較簡(jiǎn)單。
@using System.Configuration @using YLW.MS2.Common @using StructureMap @model YLW.MS2.Web.Models.LogOnModel@{ViewBag.Title = "LogOn";Layout = "~/Views/Shared/_Layout.cshtml"; }<div class="error-container"><ul>@Html.ValidationSummary(true,"登錄失敗!請(qǐng)檢查!")@if (TempData.ContainsKey("errorMessage")){Html.Raw(TempData["errorMessage"].ToString());}@if (ViewData.ContainsKey("errorMessage")){Html.Raw(ViewData["errorMessage"].ToString());}</ul></div><form name="login" id="login" method="post" action="@Url.Action("LogMeIn", "Account", new { area="MS2Auth"})"><div>@Html.TextBoxFor(m=>m.UserName)@Html.ValidationMessageFor(m=>m.UserName)</div><div>@Html.PasswordFor(m=>m.Password)@Html.ValidationMessageFor(m=>m.Password)</div><div><button type="submit" class="button" οnclick="CheckUser();return false" value="Log In"></button></div></form><script type="text/javascript">function CheckUser(){$.ajax({type: "POST",url: "@Url.Action("LogOn","Account")",data: { Email: $("#UserName").val(), password: $("#Password").val(), IsLogin: 'true' },dataType: "text json",crossDomain: false,cache: false,async: true,success: function (result) {if (result.Data) {}else{}}});}</script>?
? 里面很 簡(jiǎn)單,就是一個(gè) 提交表單,其中注意一下 如果 是自己DEBUG環(huán)境的話,記得吧把 IsLogin設(shè)為TRUE,當(dāng)然,這個(gè)是暫時(shí)的。
總結(jié)
以上是生活随笔為你收集整理的ASP.NET MVC 登录验证的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 运行及总结
- 下一篇: WCF技术剖析之五:利用ASP.NET兼