首页 > 代码库 > 一步一步实现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验证登录