2004-9-21+ Forms验证的过程
在web.config里做好设定,在ui层做好反应机制,接下来就可以把自己的web程序交给Forms验证来保护了,下面就来看Forms验证发挥作用的过程。
首先,每当我们发送一个页面的请求,都会激发数个应用程序级(Application)的事件,其中和用户验证有关的是AuthenticateRequest,打开Global.asax.cs就可以看到它
void Application_AuthenticateRequest(Object sender, EventArgs e)
每次请求发送过来,都会进入这个处理方法里面,我们可以加入以下的代码,然后在第一句的位置设置断点,来查看一下他们的值,这样就会有清晰的认识啦
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
//获得请求发送者
HttpApplication app=(HttpApplication)sender;
// 检查是否通过验证
if(app.Request.IsAuthenticated)
{
//在这里查看类型
if(app.Context.User is System.Security.Principal.GenericPrincipal)
if(app.Context.User.Identity.Name=="xx")
{}
}
}
从第一句那里就设断点,然后用f10步进查看各个的值,也可以把那些重要的添加到监视,比如app.Context.User和app.Context.User.Identity
先说一下app.Context.User就相当于我们在ui层里使用的this.User。
当请求第一次发过来的时候,也就是没有通过验证的时候,这个时候是没有调用FormsAuthentication.SetAuthCookie()的,注意看app.Context.User“未定义的值”,而app.Context.User.Identity根本不存在。
然后进入login.aspx, 填好信息后,提交,检查信息,若有问题,则打回去,否则就调用FormsAuthentication.SetAuthCookie将用户凭证赋给当前用户
通过验证后,再次进入该方法,这时监视窗口里的信息为:
app.Context.User
{System.Security.Principal.GenericPrincipal}
System.Security.Principal.IPrincipal
app.Context.User.Identity
{System.Web.Security.FormsIdentity}
System.Security.Principal.IIdentity
很明显,在获得用户凭证后,app.Context.User是GenericPrincipal类型,而app.Context.User.Identity是FormsIdentity类型。
GenericPrincipal的Identity返回一个实现IIdentity接口的对象,具体返回的值就看你在web.config里的设定,在这里当然就是返回FormsIdentity
再接着往下想,一开始我们是用app.Request.IsAuthenticated检查,通过反射器查看的该方法的实现为:
public bool IsAuthenticated
{
get
{
if ((this._context.User != null) && (this._context.User.Identity != null))
{
return this._context.User.Identity.IsAuthenticated;
}
return false;
}
}
这就是为什么不直接用app.Context.User.Identity.IsAuthenticated的原因,因为它在里面替我们检查了app.Context.Use是否已经存在,而实际上,如果app.Context.User存在了,那肯定是通过验证了,即调用了FormsAuthentication.SetAuthCookie()方法,下面是其实现:
public static void SetAuthCookie(string userName, bool createPersistentCookie)
{
FormsAuthentication.Initialize();
FormsAuthentication.SetAuthCookie(userName, createPersistentCookie, FormsAuthentication.FormsCookiePath);
}
public static void SetAuthCookie(string userName, bool createPersistentCookie, string strCookiePath)
{
FormsAuthentication.Initialize();
HttpContext.Current.Response.Cookies.Add(FormsAuthentication.GetAuthCookie(userName, createPersistentCookie, strCookiePath));
}
我们大多使用的是重载的第一个方法,它在里面调用了第二个方法,最关键的就是设定cookie那句啦,而不难想到,在Initialize()肯定是有对app.Context.User的初始化。
汗……我发现我的表达能力越来越差了,再说下去恐怕自己都糊涂了,就在这里结尾吧。下面是我的总结:
当用户没有通过验证时,一切都没有发生,根据web.config里各location的权限设定来加以保护,一旦用户填写完login.aspx的表单提交,并且通过验证,则调用FormsAuthentication.SetAuthCookie(),在这个方法里,设定了表示用户凭证的cookie,并且重新设定了Context的实例,以后就可以直接通过该Context的实例获得对实现IPrincipal接口的GenericPrincipal对象和实现IIdentity接口的FormsIdentity对象的访问。
絮絮叨叨的写了这么多,不知大家明白了没有……其实认识这个过程,关键是为使用自己的验证体系做准备,当我们要自己实现IPrincipal和IIdentity来使用自定义的验证体系时,比如分别是REDPrincipal和REDIdentity,那就要考虑转换的问题,因为默认是转成了GenericPrincipal和FormsIdentity。而转换的最佳地点就是在Application_AuthenticateRequest()方法里。
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
HttpApplication app=(HttpApplication)sender;
if(app.Request.IsAuthenticated)
{
if(!(app.Context.User is Business.RedPrincipal))
{
app.Context.User=new Business.RedPrincipal(app.Context.User.Identity.Name);
}
}
}