Login控制器,和SkipCheckLoginAttribute过滤器

1

LoginController.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace FB.CMS.MvcSite.Areas.admin.Controllers
{
    using FB.CMS.Model.ModelView;
    using FB.CMS.IServices;
    using FB.CMS.MvcSite.Filter;
    using FB.CMS.WebHelper;
    using FB.CMS.Common;

    using System.Web.WebPages;
    using FB.CMS.WebHelper.Attribute;
    using FB.CMS.Model;
    [SkipCheckLogin]
    public class LoginController : BaseController //注意:这里的控制器是继承了FB.CMS.WebHelper这个类库中的BaseController控制器
    {
        public LoginController(IsysUserInfoServices dal)
        {
            base.sysUserInfoServices = dal;
        }
        [HttpGet]
        [SkipCheckLogin]
        public ActionResult Login()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Login(LoginView model)
        {

            try
            {
                if (model.LoginName.IsEmpty())
                {
                    return base.WriteError("用户名不能为空");
                }
                if (model.LoginPWD.IsEmpty())
                {
                    return base.WriteError("密码不能为空");
                }
                string md5Pwd = MD5.MD5Entry(model.LoginPWD);

                //根据用户提供的用户名与密码,去数据库中查询,看能否查询到用户数据
                sysUserInfo uinfo = sysUserInfoServices.QueryWhere(r => r.uLoginName == model.LoginName && r.uLoginPWD == md5Pwd).FirstOrDefault();

                string vcode = Session[Keys.Vcode].ToString();

                if (uinfo == null)
                {
                    return base.WriteError("用户名或密码错误");
                }
                if (string.IsNullOrEmpty(vcode) || string.Equals(vcode, model.VCode, StringComparison.InvariantCultureIgnoreCase) == false)
                {
                    return base.WriteError("验证码错误,请重新输入");
                }

                Session[Keys.uinfo] = uinfo;

                //以下就是记录密码的功能了(免登陆功能)
                if (model.IsReMember == true)
                {
                    HttpCookie cookie = new HttpCookie(Keys.isremember, uinfo.uID.ToString());

                    //设置cookie的过期时间为7天
                    cookie.Expires = DateTime.Now.AddDays(7);
                    Response.Cookies.Add(cookie);
                }
                else
                {
                    HttpCookie cookie = new HttpCookie(Keys.isremember, "");
                    cookie.Expires = DateTime.Now.AddYears(-3);
                    Response.Cookies.Add(cookie);

                }


                return base.WriteSuccess("登陆成功,正跳转到首页");
            }
            catch (Exception ex)
            {
                return base.WriteError(ex);
            }

        }

        public ActionResult Logout()
        {
            if (Session[Keys.uinfo] != null)
            {
                Session[Keys.uinfo] = null;
                Session.Abandon();
            }

            HttpCookie cookie = new HttpCookie(Keys.isremember, "");
            cookie.Expires = DateTime.Now.AddYears(-3);
            Response.Cookies.Add(cookie);

            return RedirectToAction("Login");
        }
    }
}


FB.CMS.WebHelper类库
SkipCheckLoginAttribute.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FB.CMS.WebHelper.Filters
{
    using System.Web.Mvc;
    using FB.CMS.Common;
    using FB.CMS.IServices;
    using FB.CMS.Model.ModelView;
    using Autofac;
    using System.Web.WebPages;
    using FB.CMS.WebHelper.Attribute;
    using FB.CMS.Model;
    public class LoginCheckAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
         {
          
            string controllerNam = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
            //如果控制器类上有SkipCheckLoginAttribute特性标签,则直接return
            if (filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(SkipCheckLoginAttribute), false))
            {
                
                return;
            }
            //如果控action方法上有SkipCheckLoginAttribute特性标签,则直接return
             if (filterContext.ActionDescriptor.IsDefined(typeof(SkipCheckLoginAttribute), false))
            {
                return;
            }

            //sysUserInfo u = filterContext.HttpContext.Session[Keys.uinfo] as sysUserInfo;
            //如果控制器和action方法上都没有打SkipCheckLoginAttribute特性标签,则检查登陆Session是否存在
            if (filterContext.HttpContext.Session[Keys.uinfo]==null)
            {
                //如果用户没有做过记住密码的功能。则跳到登陆页面
                if (filterContext.HttpContext.Request.Cookies[Keys.isremember] == null)
                {
                    filterContext.HttpContext.Response.Redirect("/admin/Login/Login");
                    

                }
               

                //获取cookie中存好的用户ID(这里之所以用AInt()这个方法来将字符串转换成int类型,
                //是因为如果Cookies[Keys.isremember不存在的话,那么取到的是一个null值,如果用int.Parse(null)就会报错,
                //而用AsInt()方法,即便转换不成功,也会返回一个0,这样就不会出错了
                string uid = filterContext.HttpContext.Request.Cookies[Keys.isremember].Value;
                int userid = uid.AsInt();

                var container = CacheMgr.GetData(Keys.autofac); //从缓存中获取AutoFac的工作容器
                IsysUserInfoServices uinfo = container.Resolve();//从容器中获取IsysUserInfoServices类实例对象

                sysUserInfo userinfo = uinfo.QueryWhere(r => r.uID == userid).FirstOrDefault();//调用IsysUserInfoServices类的QueryWhere方法

                if (userinfo == null)
                {
                    //即便浏览器传递了一个Coookie[keys.isremember]过来,但是我们根据这个cookie的键得到值,
                    //经过数据库的查询,发现没有此用户,所以还需要跳转到登陆页面(Coookie[keys.isremember]里面保存的是用户的uId)                   
                    filterContext.HttpContext.Response.Redirect("/admin/Login/Login");
                    return;
                }

                filterContext.HttpContext.Session[Keys.uinfo] = userinfo;

            }
            else
            {
                return;
            }
        }

    }
}


FB.CMS.Common类库
CacheMgr.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace FB.CMS.Common
{
    public class CacheMgr
    {
        /// 
        /// 根据指定key获取缓存数据
        /// 
        /// 
        /// 
        /// 
        public static T GetData(string key)
        {
          return  (T)HttpRuntime.Cache.Get(key);
        }

        /// 
        /// 将数据存入到缓存中,只有IIS重启后才销毁
        /// 
        /// 
        /// 
        public static void SetData(string key, object obj)
        {
            HttpRuntime.Cache[key] = obj;
        }

        /// 
        /// 手工移除指定key的缓存数据
        /// 
        /// 
        public static void RemoveData(string key)
        {
            HttpRuntime.Cache.Remove(key);
        }
    }
}


FB.CMS.MvcSite项目下的App_Start文件夹
Autofac 自动工厂的配置

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace FB.CMS.MvcSite.App_Start
{
    using Autofac;
    using Autofac.Integration.Mvc;
    using FB.CMS.Common;
    using System.Reflection;
    using System.Web.Mvc;

    /// 
    /// 这个类是我自己定义的一个类,主要用初始化AutoFac容器的相关数据
    /// 
    public class AutoFacConfig
    {
        public static void Register()
        {
            //初始化AutoFac的相关功能
            /*
             1.0 告诉AutoFac初始化数据仓储层FB.CMS.Repository.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
             2.0 告诉AutoFac初始化业务逻辑层FB.CMS.Services.dll中所有类的对象实例。这些对象实例以其接口的形式保存在AutoFac容器中
             3.0 将MVC默认的控制器工厂替换成AutoFac的工厂
             */

            //第一步: 构造一个AutoFac的builder容器
            var builder = new ContainerBuilder();

            //第二步:告诉AutoFac控制器工厂,控制器类的创建去哪些程序集中查找(默认控制器工厂是去扫描bin目录下的所有程序集)
            //2.1 从当前运行的bin目录下加载FB.CMS.MvcSite.dll程序集
            Assembly controllerAss = Assembly.Load("FB.CMS.MvcSite");

            //2.2 告诉AutoFac控制器工厂,控制器的创建从controllerAss中查找(注意:RegisterControllers()方法是一个可变参数,如果你的控制器类的创建需要去多个程序集中查找的话,那么我们就再用Assembly controllerBss=Assembly.Load("需要的程序集名")加载需要的程序集,然后与controllerAss组成数组,然后将这个数组传递到RegisterControllers()方法中)
            builder.RegisterControllers(controllerAss);



            //第三步:告诉AutoFac容器,创建项目中的指定类的对象实例,以接口的形式存储(其实就是创建数据仓储层与业务逻辑层这两个程序集中所有类的对象实例,然后以其接口的形式保存到AutoFac容器内存中,当然如果有需要也可以创建其他程序集的所有类的对象实例,这个只需要我们指定就可以了)

            //3.1 加载数据仓储层FB.CMS.Repository这个程序集。
            Assembly repositoryAss = Assembly.Load("FB.CMS.Repository");
            //3.2 反射扫描这个FB.CMS.Repository.dll程序集中所有的类,得到这个程序集中所有类的集合。
            Type[] rtypes = repositoryAss.GetTypes();
            //3.3 告诉AutoFac容器,创建rtypes这个集合中所有类的对象实例
            builder.RegisterTypes(rtypes)
                .AsImplementedInterfaces(); //指明创建的rtypes这个集合中所有类的对象实例,以其接口的形式保存
           

            //3.4 加载业务逻辑层FB.CMS.Services这个程序集。
            Assembly servicesAss = Assembly.Load("FB.CMS.Services");
            //3.5 反射扫描这个FB.CMS.Services.dll程序集中所有的类,得到这个程序集中所有类的集合。
            Type[] stypes = servicesAss.GetTypes();
            //3.6 告诉AutoFac容器,创建stypes这个集合中所有类的对象实例
            builder.RegisterTypes(stypes)
                .AsImplementedInterfaces(); //指明创建的stypes这个集合中所有类的对象实例,以其接口的形式保存



            //第四步:创建一个真正的AutoFac的工作容器
            IContainer container = builder.Build();

            //4.1将container存入全局缓存对象HttpRuntime.Cache[Keys.autofac]中
            CacheMgr.SetData(Keys.autofac, container);

            // 从Autofac容器内部根据指定的接口 IsysFunctionServices 获取其实现类的对象实例
            //var obj = container.Resolve();



            //我们已经创建了指定程序集的所有类的对象实例,并以其接口的形式保存在AutoFac容器内存中了。那么我们怎么去拿它呢?
            //从AutoFac容器内部根据指定的接口获取其实现类的对象实例
            //假设我要拿到IsysFunctionServices这个接口的实现类的对象实例,怎么拿呢?
            //var obj = container.Resolve(); //只有有特殊需求的时候可以通过这样的形式来拿。一般情况下没有必要这样来拿,因为AutoFac会自动工作(即:会自动去类的带参数的构造函数中找与容器中key一致的参数类型,并将对象注入到类中,其实就是将对象赋值给构造函数的参数)


            //第五步:将当前容器中的控制器工厂替换掉MVC默认的控制器工厂。(即:不要MVC默认的控制器工厂了,用AutoFac容器中的控制器工厂替代)此处使用的是将AutoFac工作容器交给MVC底层 (需要using System.Web.Mvc;)
            DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

            //我们知道控制器的创建是调用MVC默认的控制器工厂,默认的控制器工厂是调用控制器类的无参构造函数
            //可是我们如果要使用AutoFac自动工厂,将对象通过构造函数注入类中,那么这个构造函数就需要带参数
            //如果我们将控制器的无参构造函数删除,保留带参数的构造函数,MVC默认的控制器工厂来创建控制的时候
            //就会去调用无参的构造函数,可是这时候发现没有无参的构造函数于是就报“没有为该对象定义无参数的构造函数”错误
            //既然报错,那我们如果保留无参的构造函数,同时在声明一个带参数的构造函数是否可行呢?
            //答案;行是行,但是创建控制器的时候,MVC默认的控制器工厂调用的是无参构造函数,它并不会去调用有参的构造函数
            //这时候,我们就只能将AutoFac它的控制器工厂替换调用MVC默认的控制器工厂(控制器由AutoFac的控制器工厂来创建)
            //而AutoFac控制器工厂在创建控制的时候只会扫描带参数的构造函数,并将对象注入到带参数的构造函数中
            //AutofacDependencyResolver这个控制器工厂是继承了 IDependencyResolver接口的,而IDependencyResolver接口是MVC的东西
            //MVC默认的控制器工厂名字叫:DefaultControllerFactory
            //具体参考:http://www.cnblogs.com/artech/archive/2012/04/01/controller-activation-032.html

            //关于自动注入也可以参考:http://www.cnblogs.com/n-pei/archive/2013/01/24/2875674.html

            //可以参考:http://www.360doc.com/content/14/1103/17/1039473_422223837.shtml

        }
    }
}


FB.CMS.MvcSite项目下
Global.asax

using FB.CMS.MvcSite.App_Start;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace FB.CMS.MvcSite
{
    // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
    // 请访问 http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AutoFacConfig.Register(); //执行自动工厂
        }
    }
}


你可能感兴趣的:(Mvc)