在我的上一篇《使用HttpContext中的User属性来实现用户身份验证》中已经讲了怎样来使用HttpContext.User属性来实现用户身份验证,并且还写了一个示例程序。但是,在上一篇文章中,我们使用的是系统缓存来保存用户的登录信息,这无疑是占用系统资源的一种做法,那有没有更好的办法呢?我在上一章中说过大家可以尝试使用用户验证票的方式来保存用户登录信息的,这种方式是基于Cookie原理来实现的,因此避免了使用缓存所带来的困扰。我们已经有了上一篇的基础,这次只需要在它的基础上稍加修改就可以了。
要使用这种方法,我们首先要配置web.config文件,把<authentication>节点的属性mode改为Forms,再在该节点中添加<forms name="ContextUser" loginUrl="~\WebForm1.aspx" protection="None" slidingExpiration="true" />,这些代表的意思可以在MSDN上查到,这里就不多作解释了。
下面是修改后的代码:
MyPage.cs
using System;
using System.Collections;
namespace HttpContextUserEG
{
/// <summary>
/// MyPage 的摘要说明。
/// </summary>
/// 继承自Page类
public class MyPage : System.Web.UI.Page
{
public MyPage()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
protected override void OnInit(EventArgs e)
{
base.OnInit (e);
this.Load +=new EventHandler(MyPage_Load);
}
//在页面加载的时候从缓存中提取用户信息
private void MyPage_Load(object sender, System.EventArgs e)
{
if(Context.User.Identity.IsAuthenticated)
{
if(!(Context.User is MyPrincipal))
{
MyPrincipal principal = new MyPrincipal(Context.User.Identity.Name);
Context.User = principal;
}
}
}
}
}
MyPrincipal.cs
using System;
using System.Collections;
namespace HttpContextUserEG
{
/// <summary>
/// MyPrincipal 的摘要说明。
/// </summary>
/// 实现IPrincipal接口
public class MyPrincipal : System.Security.Principal.IPrincipal
{
private System.Security.Principal.IIdentity identity;
private ArrayList roleList;
public MyPrincipal(string userID)
{
//
// TODO: 在此处添加构造函数逻辑
//
identity = new MyIdentity(userID);
roleList = new ArrayList();
roleList.Add("Admin");
}
public static MyPrincipal ValidateLogin(string userID,string password)
{
if(userID == "yan0lovesha" && password == "iloveshasha")
{
return new MyPrincipal(userID);
}
else
return null;
}
public ArrayList RoleList
{
get
{
return roleList;
}
}
#region IPrincipal 成员
public System.Security.Principal.IIdentity Identity
{
get
{
// TODO: 添加 MyPrincipal.Identity getter 实现
return identity;
}
set
{
identity = value;
}
}
public bool IsInRole(string role)
{
// TODO: 添加 MyPrincipal.IsInRole 实现
return roleList.Contains(role);;
}
#endregion
}
}
MyIdentity.cs
using System;
namespace HttpContextUserEG
{
/// <summary>
/// MyIdentity 的摘要说明。
/// </summary>
/// 实现IIdentity接口
public class MyIdentity : System.Security.Principal.IIdentity
{
private string userID;
private string password;
public MyIdentity(string currentUserID)
{
//
// TODO: 在此处添加构造函数逻辑
//
userID = currentUserID;
password = "iloveshasha"; //这里实际上是从数据库中获得的密码
}
private bool CanPass()
{
//这里朋友们可以根据自己的需要改为从数据库中验证用户名和密码,
//这里为了方便我直接指定的字符串
if(userID == "yan0lovesha" && password == "iloveshasha")
{
return true;
}
else
{
return false;
}
}
public string Password
{
get
{
return password;
}
set
{
password = value;
}
}
#region IIdentity 成员
public bool IsAuthenticated
{
get
{
// TODO: 添加 MyIdentity.IsAuthenticated getter 实现
return true;
}
}
public string Name
{
get
{
// TODO: 添加 MyIdentity.Name getter 实现
return userID;
}
}
//这个属性我们可以根据自己的需要来灵活使用,在本例中没有用到它
public string AuthenticationType
{
get
{
// TODO: 添加 MyIdentity.AuthenticationType getter 实现
return null;
}
}
#endregion
}
}
WebForm.aspx.cs
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.Caching;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace HttpContextUserEG
{
/// <summary>
/// WebForm1 的摘要说明。
/// </summary>
/// 将这里本来继承自Page类改为继承自我们自己的MyPage类
public class WebForm1 : HttpContextUserEG.MyPage
{
protected System.Web.UI.WebControls.TextBox tbxUserID;
protected System.Web.UI.WebControls.TextBox tbxPassword;
protected System.Web.UI.WebControls.Panel Panel1;
protected System.Web.UI.WebControls.Button btnAdmin;
protected System.Web.UI.WebControls.Button btnUser;
protected System.Web.UI.WebControls.Label lblRoleMessage;
protected System.Web.UI.WebControls.Label lblLoginMessage;
protected System.Web.UI.WebControls.Button btnLogin;
private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
}
#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
this.btnAdmin.Click += new System.EventHandler(this.btnAdmin_Click);
this.btnUser.Click += new System.EventHandler(this.btnUser_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void btnLogin_Click(object sender, System.EventArgs e)
{
MyPrincipal principal = MyPrincipal.ValidateLogin(tbxUserID.Text,tbxPassword.Text);
if(principal == null)
{
lblLoginMessage.Text = "用户名或密码不正确";
Panel1.Visible = false;
}
else
{
// 如果用户通过验证,则生成用户验证票
Context.User = principal;
System.Web.Security.FormsAuthentication.SetAuthCookie(tbxUserID.Text,true);
lblLoginMessage.Text = tbxUserID.Text + "已经登录";
Panel1.Visible = true;
}
}
private void btnAdmin_Click(object sender, System.EventArgs e)
{
// 验证用户的Role中是否包含Admin
if(Context.User.IsInRole("Admin"))
{
lblRoleMessage.Text = "用户" + ((MyPrincipal)Context.User).Identity.Name + "属于Admin组";
}
else
{
lblRoleMessage.Text = "用户" + Context.User.Identity.Name + "不属于Admin组";
}
}
private void btnUser_Click(object sender, System.EventArgs e)
{
// 验证用户的Role中是否包含User
if(Context.User.IsInRole("User"))
{
lblRoleMessage.Text = "用户" + Context.User.Identity.Name + "属于User组";
}
else
{
lblRoleMessage.Text = "用户" + Context.User.Identity.Name + "不属于User组";
}
}
}
}
WebForm.aspx不需要修改
大家可以对比这两篇代码的不同来理解这种用户验证机制!