一步一步实现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="" />
</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();
} string Role = string.Empty; switch (role)//这里简要这几个角色,实际应用中可以从数据库中读取角色
{
case :
Role = "Agent";//客户
break;
case :
Role = "Business";//供应商
break;
case :
Role = "Financial";//财务
break;
case :
Role = "Boss";//老板
break;
} //生产身份验证
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(,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, );
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, );
}
}
else
{
status = new Tuple<EnumList.LoginSts, int>(EnumList.LoginSts.NoExists, );
}
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 == )
{
//对登录成功的情况进行处理,可以跳转到列表页或者网站首页之类的
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(-);
HttpContext.Current.Response.Cookies.Add(cookie);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Session.Abandon();
FormsAuthentication.SignOut();
}
代码很简单,就是清除Cookie,清除Cookie的方法就是将它的过期时间设置为前一天。然后FormsAuthentication.SignOut()就退出了。
整个流程完成,前台页面的代码就不写了,就两个文本框加上一个登录按钮。还有一个是否自动登录的按钮,这里就不演示了。
一步一步实现FormsAuthentic验证登录的更多相关文章
- 一步一步来做WebQQ机器人-(三)(登录QQ并保持在线)
× 本篇的目的是让你的QQ真正的上线:挤下你的PCQQ,和让好友状态栏显示webqq在线 目前总进度大概50% 全系列预计会有这些步骤,当然某些步骤可能会合并: 验证码 第一次登陆 第二次登陆 保持在 ...
- 一步一步从原理跟我学邮件收取及发送 2.邮箱的登录和绕不开的base64
一步一步从原理跟我学邮件收取及发送 2.邮箱的登录和绕不开的base64 好了,经过本系列上一篇文章 "1.网络命令的发送",假设大家已经掌握了 email 电子邮件的命令发送的方 ...
- xilinx IP核配置,一步一步验证Xilinx Serdes GTX最高8.0Gbps
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010161493/article/details/77658599 目录(?)[+] 之前 ...
- xmppmini 项目详解:一步一步从原理跟我学实用 xmpp 技术开发 2.登录的实现
第二章登录的实现 金庸<倚天屠龙记> 张三丰缓缓摇头,说道:“少林派累积千年,方得达成这等绝技,决非一蹴而至,就算是绝顶聪明之人,也无法自创.”他顿了一顿,又道:“我当年在少林寺中住过,只 ...
- 一步一步来做WebQQ机器人-(二)(第一次登陆)
// 预计会有这些步骤,当然某些步骤可能会合并: 验证码 第一次登陆 第二次登陆 保持在线和接收消息 获取好友和群列表 发送消息 变成智能的(*゚∀゚*) webqq的登陆,分为2步,本文主要讲第一次 ...
- 一步一步实现MVC5+EF6+Bootstarp+Autofac+NoSql实现OADemo 之登陆(一) 验证码 Captcha 之大插件小用
不知何年何月才能完成OADemo啊,总之还是一步一步来吧,这段时间开始着手了,先做登陆. 前段时间研究了一下在CentOS7下安装Mysql和Memcached服务,并测试了用C#操作,结果还行. ...
- 一步一步教你将普通的wifi路由器变为智能广告路由器
一步一步教你将普通的wifi路由器变为智能广告路由器 相信大家对WiFi智能广告路由器已经不再陌生了,现在很多公共WiFi上网,都需要登录并且验证,这也就是WiFi广告路由器的最重要的功能.大致就是下 ...
- 一步一步创建ASP.NET MVC5程序[Repository+Autofac+Automapper+SqlSugar](八)
前言 Hi, 大家好,还是星期五,还是Rector,又在图享网准时和大家见面了. 今天给大家带来系列教程<一步一步创建ASP.NET MVC5程序[Repository+Autofac+Auto ...
- jQuery一步一步实现跨浏览器的可编辑表格,支持IE、Firefox、Safari、
脚 本 之 家 www.jb51.net 脚本云 专题 素材下载 电子书 软件下载 源码下载 服务器常用软件 a5交易 首页 网页制作 脚本专栏 脚本下载 网络编程 数据库 CMS教程 电子书籍 平面 ...
随机推荐
- String类的一些方法
String 类有以下方法: startsWith(String prefix) boolean java.lang.String.startsWith(String prefix) Tests if ...
- linux 远程桌面工具NX
1.在linux服务器上需要安装3个文件,下载地址为: http://www.nomachine.com/download-package.php?Prod_Id=1977 nxclient-3.4. ...
- 2-SAT 及 一点习题
今天简单学习了一下2-SAT.现在简单地总结一下.至于定义之类的就不写了,这里就写写做法,以防以后忘记. 构图 每个值a,拆为两个点,一个表示a,一个表示^a(非a).每个点我们可以看成是一个命题(这 ...
- socket通信技术介绍
[-] 网络中进程之间怎样通信 什么是Socket socket一词的起源 socket的基本操作 socket函数 bind函数 网络字节序与主机字节序 listenconnect函数 accept ...
- mongodb进阶一之高级查询
上篇文章我们讲了mongodb的crud基本操作 http://blog.csdn.net/stronglyh/article/details/46812579 这篇我们来说说mongodb的进阶-- ...
- 学习MongoDB 二:MongoDB加入、删除、改动
一.简单介绍 MongoDB是一个高性能.开源.无模式的文档型数据库,是当前NoSQL数据库产品中最热门的一种.数据被分组存储在数据集中,被称为一个集合(Collenction)和对于存储在Mongo ...
- 使用gson(一)
1.数组和json的转换 package com.test.gson; import com.google.gson.Gson; public class ArrayToJson { public s ...
- Qt删除指定文件
Qt删除指定文件: QFile fileTemp(filename); fileTemp.remove();
- BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )
这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------- ...
- 一天一个类--ArrayList之二
继续我的小激动--- 1.看看构造一个ArrayList 有两种方式 一个指定大小,一个不指定.我们知道他其实使用数组来实现了,数组肯定要有大小,那么他没指定大小,默认的是多少呢???追踪源码---开 ...