zoukankan      html  css  js  c++  java
  • 一步一步实现FormsAuthentic验证登录

      本文不讲原理,只讲用法,原理性的东西网上特别多,不过还是会对一些要用到的东西进行解释,不深入讲原理。本文中用的是Vs2012   .net mvc 4.0。原理看这篇文章,看完这个文章绝对受益匪浅。

    说下登录的整个流程:用户输入账号密码->点击提交->数据提交到后台控制器->去数据库取得用户资料->如果登录成功->将数据写入cookie(也就是写入forms身份验证)->返回给控制器登录状态->对相应的登录状态进行处理。

    第一步:新建一个.net mvc 4.0的解决方案,然后配置 WebConfig文件

    在 <system.web>节点下添加以下代码:

        <authentication mode="Forms" name="CookieName">
          <forms loginUrl="~/Login/Login" timeout="2880" />
        </authentication>

    简要说明 一下上面的代码:

      loginUrl登录页的URL。通过FormsAuthentication.LoginUrl属性可以得到该配置值。当调用FormsAuthentication.RedirectToLoginPage()方法时,客户端请求将被重定向到该属性所指定的页面。如果没有设置这个属性,.net也会尝试在目录下寻找名为login.aspx的文件;

      mode属性,就是选择的是Forms模式的登录,还有其他模式(Windows,Passport等等);

      name属性,是cookie的名称,在获取登录的cookie时需要通过这个name来取得登陆用的Cookie;

      timeout属性,就是Cookie的过期时间,可以同slidingExpiration属性 配合使用;

      slidingExpiration属性,是否启用“弹性过期时间”,如果该属性设置为false,从首次验证之后过timeout时间后Cookie即过期;如果该属性为true,则从上次请求该开始过timeout时间才过期,也就是说,如果在timeout时间内,再次向服务器端发送请求,则Cookie将永远不会过期。

    以上是主要用到的一些属性。

    关于配置文件,若有数据库,当然还要配置数据库连接,这里就不多说了。

    第二步:创建用户类型:UserModel

      这个类主要是用来保存登录的用户的对象。

        /// <summary>使用者</summary>
        public class UserModels
        {
            /// <summary>使用者编号</summary>
            [Display(Name = "使用者编号")]
            public int users_db_id { get; set; }
    
            /// <summary>用戶姓名</summary>
            [Display(Name = "用户姓名")]
            public string users_name { get; set; }
    
            /// <summary>账号</summary>
            [Display(Name = "账号")]
            public string login_id { get; set; }
    
            /// <summary>密码</summary>
            [Display(Name = "密码")]
            public string login_pwd { get; set; }
    
            /// <summary>身分</summary>
            [Display(Name = "身份")]
            public int users_position { get; set; }
        }

    在这里不对角色做太多的处理,users_position简要的表明用户所属的角色。

    第三步:添加一个生产身份验证的类SetCookies

    public class SetCookies
        {
            public static void SetCookie(string id, bool chkAutoLogin, int role)
            {
                DateTime EndDate = DateTime.Now;
                if (chkAutoLogin)
                {
                    EndDate = DateTime.Now.AddDays(14);
                }
    
                string Role = string.Empty;
    
                switch (role)//这里简要这几个角色,实际应用中可以从数据库中读取角色
                {
                    case 1:
                        Role = "Agent";//客户
                        break;
                    case 2:
                        Role = "Business";//供应商
                        break;
                    case 3:
                        Role = "Financial";//财务
                        break;
                    case 4:
                        Role = "Boss";//老板
                        break;
                }
    
                //生产身份验证
                FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,id,DateTime.Now,EndDate,true,Role,FormsAuthentication.FormsCookiePath);
                
                //对身份验证的标识进行加密
                string encTicket = FormsAuthentication.Encrypt(ticket);
    
                //创建将要写入到客户端的Cookie            
                HttpCookie newCookie = new HttpCookie(FormsAuthentication.FormsCookieName, id);
           //如果勾选了是否自动登录,则将过期时间推迟14天
                if (chkAutoLogin)
                {
                    newCookie.Expires = EndDate;
                }
                //写入到客户端
                HttpContext.Current.Request.Cookies.Add(newCookie);
            }
        }
    FormsAuthentication.FormsCookieName 就是刚才在配置文件中的name属性的值
    这里小写的role 类似于数据库用户表的外键(一般都有一个权限表,这里假设只有用户表和角色表),大写的Role类似于数据库角色表的角色名称,这里简要处理角色,所以在真正项目中,可以在这里从数据库读取用户的角色,然后将其角色用逗号(或者其他符号隔开),生产一个角色字符串(类似于Role="角色A,角色B,角色C")。最后将这个Role传到FormsAuthenticationTicket 类的UserData参数中,在后面判断角色的时候用到,UserData这个参数也不一定要放角色,也可以放其他要用到的数据,因项目而异。对FormsAuthenticationTicket 这个类不清楚的,可以自己看看定义(最好还是去看看,对理解这个Forms验证登录有帮助)。以上这个类也算是Forms登录中最重要的一步了。
    第三步:验证登录,从数据库拿数据,然后返回登录状态
    先给出登录状态的类,这是一个枚举类型
        public class EnumList
        {
            public enum LoginSts
            {
                /// <summary>登入成功</summary>
                Sucess,
                /// <summary>密碼錯誤</summary>
                PasswordError,
                /// <summary>帳號不存在</summary>
                NoExists,        
                /// <summary>登入失敗</summary>
                LoginError
            }
        }

    这个是枚举类型,不做解释。

     public class SetLoginRepository
        {
            public static Tuple<EnumList.LoginSts, int> SetLogin(string id, string pwd = "", bool IsAutoLogin = false)
            {
           //关于以下这种类型的用法,请看另一篇文章,或者网上搜索Tuple,没有这个类型对本文章没有多大的影响,因为这个类型就是用来返回 多种数据类型 的数据 的类型 Tuple
    <EnumList.LoginSts, int> status = new Tuple<EnumList.LoginSts, int>(EnumList.LoginSts.LoginError, 0); UserModels userData = GetUserData(id);//取得用户数据 if (userData != null) { if (string.IsNullOrWhiteSpace(pwd) || userData.login_pwd == pwd) { //你可以在这里将登录的用户对象存放到Session中,以便将来要用到这个对象,比如Session["Account"]=userData SetCookies.SetCookie(id, IsAutoLogin, userData.users_position);//这里就是调用上面的那个写入身份验证的方法 status = new Tuple<EnumList.LoginSts, int>(EnumList.LoginSts.Sucess, userData.users_position); } else { status = new Tuple<EnumList.LoginSts, int>(EnumList.LoginSts.PasswordError, 0); } } else { status = new Tuple<EnumList.LoginSts, int>(EnumList.LoginSts.NoExists, 0); } return status; }     //从数据库取得用户数据,这里使用的是Ado.net public static UserModels GetUserData(string id) { UserModels model = new UserModels(); string connStr = ConfigurationManager.ConnectionStrings["TestDB"].ConnectionString; using (SqlConnection conn = new SqlConnection(connStr)) { conn.Open(); SqlCommand cmd = conn.CreateCommand(); cmd.CommandText = "select top 1 * from users_db where login_id='" + id + "' and datastatus=1 "; SqlDataReader sdr = cmd.ExecuteReader(System.Data.CommandBehavior.SingleRow); if (sdr.Read()) { model.users_db_id = Convert.ToInt32(sdr["users_db_id"]); model.login_id = sdr["login_id"].ToString(); model.users_name = sdr["users_name"].ToString(); model.login_pwd = sdr["login_pwd"].ToString(); model.datastatus = Convert.ToBoolean(sdr["datastatus"].ToString()); model.users_position = Convert.ToInt32(sdr["users_position"]); } } return model; } }

    关于Tuple<T1,T2...T8> 的用法请看另一篇文章.Net 4.0特性 Tuple元组

    。这里先简要解释一下它的作用,Tuple就是可以自定义任何类型,在返回值的时候,可以返回任意多个类型的数据,我认为它的作用就是能返回多种类型的数据。然后可以通过该类型的实例获得相应的值,获取值的方法是比如这个类的实例叫tuple,则取得值的方法是tuple.Item1,tuple.Item2....tuple.Item8,通过这个可以取得对应位置的值。这就很方便的给我们提供了可以在一个方法里面返回多种数据类型。

    第四步:也是非常重要的一步,Global文件添加一个方法:

            //取得自定义的角色
            public void Application_AuthenticateRequest(object sender, EventArgs e) {
              if (Request.IsAuthenticated) {
                // 先取得该使用者的 FormsIdentity
                FormsIdentity id = (FormsIdentity)User.Identity;
                // 再取出使用者的 FormsAuthenticationTicket
                FormsAuthenticationTicket ticket = id.Ticket;
                // 將储存在 FormsAuthenticationTicket 中的角色定义取出,并转成字符串数组
                string[] roles = ticket.UserData.Split(new char[] { ',' });
                // 指派角色到目前这个 HttpContext 的 User 物件去
                Context.User = new GenericPrincipal(Context.User.Identity, roles);
              }
            }

    这个方法是在Global文件中定义的,在客户端每次发一个请求都会先经过这个方法,即使是Ajax请求也同样要先经过这个方法。注释写得很清楚,不多说。

    第五步 :写控制器LoginController

            public ActionResult SetLogin(string Name, string Password)
            {
                if (ModelState.IsValid)
                {
                    Tuple<EnumList.LoginSts, int> status = SetLoginRepository.SetLogin(Name, Password, true);
                    switch (status.Item1)//这个.Item1就是Tuple类型取得对应位置类型 的值 的方法
                    { 
                        case EnumList.LoginSts.Sucess:
                            if (status.Item2 == 1)
                            {
                               //对登录成功的情况进行处理,可以跳转到列表页或者网站首页之类的
                                return RedirectToAction("actionName","ControlName");
                            }
                            break;
                        case EnumList.LoginSts.NoExists:
                            //对用户不存在的情况进行处理
                            break;
                        case EnumList.LoginSts.PasswordError:
                            //对密码错误的情况进行处理
                            break;
                    }
                }
                return View();
            }        

    顺便附上退出的代码:

            public static void ClearSessionAndCookie()
            {
                HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName);
                cookie.Expires.AddDays(-1);
                HttpContext.Current.Response.Cookies.Add(cookie);
                HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);               
                HttpContext.Current.Session.Abandon();
                FormsAuthentication.SignOut();
            }

    代码很简单,就是清除Cookie,清除Cookie的方法就是将它的过期时间设置为前一天。然后FormsAuthentication.SignOut()就退出了。

    整个流程完成,前台页面的代码就不写了,就两个文本框加上一个登录按钮。还有一个是否自动登录的按钮,这里就不演示了。

     

  • 相关阅读:
    Java 1.7.0_21b11 Code Execution
    nginx NULLByte 任意代码执行漏洞
    nginx ‘ngx_http_close_connection()’远程整数溢出漏洞
    WordPress WP Super Cache插件任意代码执行漏洞
    memcached 远程拒绝服务漏洞
    原环套原环
    要去哈尔滨了
    母亲节就要到了,你忘了吗?
    对于流媒体服务的一点概念
    有了螃蟹让心情好一点
  • 原文地址:https://www.cnblogs.com/LJP-JumpAndFly/p/4150110.html
Copyright © 2011-2022 走看看