ASP.NET MVC 登录验证

   好久没写随笔了,这段时间没 什么事情,领导 一直没安排任务,索性 一直在研究代码,说实在的,这个登录都 搞得我云里雾里的,所以这次我可能也讲得不是 特别清楚,但是 我尽力把我知道的讲出来,顺便也对自己最近的工作 做义工总结吧。

  我们的项目用到的一些 技术也跟大家提一下,主要是用了NHibernate,StructureMap,FluentHibernate等等,可能这篇文章我不会 全部 提到 ,不过相信后面,如果我要写文章的话,肯定是会提到的。我自己也模仿 了公司的框架做了一个 简单的登录(未完成)的,因为感觉公司的东西实在是很复杂,所以不一定可以完全消化,所以才 写了一上午没写完 = =

  首先,登录的话,我是写在一个Area里面,至于 怎么建立Area(区域)我就 不多累赘了,Area的名字我就 取成MS2Auth,因为 自己 喜欢MapleStory这个游戏,所以取了 它的 一个缩写 单词,以下是结构。

ASP.NET MVC 登录验证

我们新建一个Controller名叫AccountController这个就是我们 登录用的主的控制器,然后再往Controller里面添加一些Action,比如我们添加一个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);

            }

        }

  大家 可能会先去关心MS2UserCheckTransferMsg这个类里面的东西。

    /// <summary>

    /// 登陆检查

    /// </summary>

    public class MS2UserCheckTransferMsg:IMessage

    {

        public string Email { get; set; }



        public string password { get; set; }



        public bool IsLogin { get; set; }



    }

一个 是Email,一个 是密码,另一个 就是“是否登录”,是否登录 是检测 如果你访问到了这个ACTION的话,如果你 已经处于登录状态了,那么就会执行下面的流程。

这里面的一个 重点是 “反射”,通过反射 去获取某个类底下的方法。这个话 怎么 去理解 呢?首先大家主营到 下面的一个 方法。

        private bool ShowpopupReminder(MS2UserCheckTransferMsg message)

        {

            var queryBus = ObjectFactory.GetInstance<IQueryBus>();

            return queryBus.Query<MS2UserCheckTransferMsg, dynamic>(message);



        }

  这里我们 通过 一个 工厂 方法去 得到IQueryBus的 一个 实例,然后 再用 这个实例反过来,去执行一个 Query的方法。

namespace YLW.MS2.Common.TransferMsg

{

    public interface IQueryBus

    {

        TResponse Query<TRequest, TResponse>(TRequest message) where TResponse : class;



    }

}

  那么 ,这个IQueryBus其实是 一个 接口,我需要 得到这个接口的一个实例,该怎么 办呢?下面就提供了一种解决方法,大家想起来那个Global.asax文件了吗,那个不是 进行初始化的一个文件吗?对的,就是 这么一个文件,我们 需要 做的,就是 在Application_Start里面进行初始化,把这些 实例先一股脑的丢进去,进行工厂化处理,然后要的时候只要 指定实例名或者 类型的话,就可以 方便的取出来。

为此我们需要用到一个东西。那 就是StructureMap的For方法,来 注册这个接口的实例。

  

        public static void Init()

        {

            ObjectFactory.Configure(x =>

            x.For<IQueryBus>().Use<LocalQueryBus>(););

        }

  当然 ,这只是一个例子而已,具体的你 如果想注册其他的东西的话,也可以 用类似的方法去 写,大家 注意到 了没有 ,有 一个 叫做IMessage的接口,这个接口里面不 包含 任何东西,我的理解就是 这个接口的作用只是作为一个 中转而用的,另 一个接口 叫做IMessageHandler,这个 接口的话里面只有一个Execute方法。也就是下面要提到的,IMESSAGE只是 作为一个转换而已 ,也就是 说 任何 实现了IMessage接口的类,不需要实现任何多余的方法,也就是说,这个只是依赖注入的一个中转站而已(我个人的理解)。

  下面的方法就是通过反射区调用Execute方法,而这个Execuute方法真正 所在的类,其实是被IMessageHanlder所 实现的接口的一个 方法。

    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 });

        }



    }

 

下面 就说明了真正执行的方法的实际位置:

public class MS2UserCheckHandler: IMessageHandler<MS2UserCheckMessage>

  总之我感觉 这种 反射 跳来跳去的,我头都有点 花了,其中具体的用法具体去 考虑,比如 那个 MakeGenericType,大家可以自己 去 查查 用法 。

  由于有些 登录的机制特别的复杂,比如有你需要 一个“公共秘钥”去登录 ,就是说你 需要 返回 一个公共密码到另一台服务器上面 去,只有你的用户名和密码以及那个公共秘钥都对了,你才能登录,这个有点 类似于支付宝的数字证书吧,虽然 没 那么 复杂。那么,我们总不可能每次都去 匹配吧?这里告诉 大家 一个简单的方法,看下面的代码。

#if DEBUG

        public ActionResult LogMeIn(LogOnModel model)

        {

            return RedirectToAction("Landing");

        }

#endif

  大家只要 用#if DEBUG #endif 代码段,就可以调试本地的了,如果是服务器上的话,就不会执行本段代码 ,这段 代码只是在 本地启动的时候才有用哦。下面告诉 大家 一种伪造 登录的方法:可以使用Request.Headers.Add()方法去添加相应的键值对,比如 你 可以 往这里面 添加 用户名,EMAIL,公共秘钥ID等,如下面的代码 所示。

            Request.Headers.Add("SM_USER", user);

            Request.Headers.Add("EMAIL", email);

  然后 进行本地调试的时候,只要把这些值取出来就行了,当然了,我这么做 也许有些人会说没意义,我的目的只是 为了模拟登录的流程而已,仅此而已。

  当然 ,你需要一个判断的过程,于是就有 了下面的方法:

        public CommandResponse Command<TRequest>(TRequest message)

        {

            var result = QueryHandlerExecute((IMessage)message);



            if (result!= null)

            {

                return (CommandResponse) result;

            }



            return  new CommandResponse();

        }

  具体的我也说不清楚,这里面感觉 还是 有点 复杂。。。

 

    public class CommandResponse

    {

        public bool Success { get; set; }



        public string Message { get; set; }

    }

  如果Success=true的话,那么就 使用下面这句话,这句话的作用就是使你的User.Identity.IsAuthenticated为True,表示 你已经通过了登录 验证。

FormsAuthentication.SetAuthCookie(model.MS2User, false);

  如果 你 没有通过验证的话,那么 还需要 往TempData里面去放一些值,跳转带到新页面 ,为什么 使用 TempData,因为登录后,错误 信息只显示一次 ,所以用TempData,当然如果 你是正常 退出的话,那么就 可以 这样 。

                System.Web.HttpContext.Current.Session.RemoveAll();

                FormsAuthentication.SignOut();

                return RedirectToAction("LogOn", "Account", new

                {

                    area = "MS2Auth"

                });

注意 在 这里 area是必须的,因为 我们把登录的接口 放到了Area里面。好久没写了,文字比较拙劣,今天试着做了下登录,没 完全做出来,希望以后能有 进一步的提高吧。

 PS:差点 忘了贴登录的View页面,比较简单。

@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,"登录失败!请检查!")

        @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" onclick="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>

 

   里面很 简单,就是一个 提交表单,其中注意一下 如果 是自己DEBUG环境的话,记得吧把 IsLogin设为TRUE,当然,这个是暂时的。

你可能感兴趣的:(asp.net)