首页 > 代码库 > 一步一步实现FormsAuthentic验证登录

一步一步实现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()就退出了。

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

 

一步一步实现FormsAuthentic验证登录