ASP.NET MVC 登录验证

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

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

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

我们新建一个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,当然,这个是暂时的。

原文地址:https://www.cnblogs.com/kmsfan/p/4602368.html