技术开发 频道

基于ASP.NET AJAX框架实现表单验证编程(实践篇)

一、 引言

    在上篇中,我们讨论了ASP.NET AJAX框架的客户端认证服务静态类AuthenticationService中主要的公共成员及其使用注意事项。在本篇中,让我们通过编写一个具体的示例程序来学习如何在基于ASP.NET AJAX框架客户端中心型的Web开发中配置与使用AuthenticationService对象。

二、 必要的服务器配置

   为了有效地处理例如用户名和密码等用户认证信息并校验这些信息。服务器端为我们提供了基础性框架。例如,ASP.NET AJAX框架中的表单认证特征就支持我们通过一个简单的登录表单来实现对于用户名及登录口令的认证。如果应用程序验证了用户请求,那么,服务器端将构建并发出一个特定“证件”—其中包含了在随后的请求中用于重建用户身份和密钥信息。

   AuthenticationService类提供了一个JavaScript代理类,我们可以从客户端脚本中调用之以实现与服务器方认证服务的通讯。

   【注意】实际开发中,我们也可以通过AuthenticationServiceManager类来创建自己的服务器端认证服务。也即是创建一个支持从客户端JavaScript脚本中进行调用的WebService。在此我们暂不讨论之。

    我们再次强调,为了操作本文示例,读者应该先学习有关ASP.NET 2.0使用Membership思想实现用户管理方面的知识。
下面,我们来讨论具体的配置。

三、 启动认证服务

(一)首先启动ASP.NET 2.0内置的身份认证服务 。

    因为ASP.NET AJAX框架的客户端认证服务基于标准的服务器端ASP.NET 2.0用户认证管理机制;所以,我们需要先通过web.config文件来启动ASP.NET 2.0本身的认证服务支持。

   打开web.config文件,找到并设置如下内容:
<system.web.extensions> 
<scripting>
<webServices>
<authenticationService enabled="true" />
</webServices>
</scripting>
</system.web.extensions>
    通过上面的设置之后,我们即可在客户端脚本中直接访问ASP.NET 2.0的身份认证服务。

    因为我们需要使用表单认证模式,所以接下来,还要在网站根目录下的web.config文件中进行如下配置:
<authentication mode="Forms"> 
<forms name="auth" loginUrl="~/MyAjaxAuthenticationService.aspx" timeout="30" protection="All" cookieless="UseCookies" path="/"></forms>
</authentication>
   至止,即为我们的示例Web站点启动了身份认证应用程序服务,且设置认证的类型为“表单”认证方式。其中的参数loginUrl设置了Web站点的初始登录页面,即“~/MyAjaxAuthenticationService.aspx”。

   【注意】必须启用浏览器端的cookies功能,因为认证服务使用cookie来临时存储在随后的请求中重建用户身份的认证信息。

四、 配置对于Membership数据库的访问

    默认情况下,ASP.NET 2.0使用一个SQL Server Express数据库来存储成员身份认证信息。与此相关的machine.config配置文件(默认位置为C:\ WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config,你可以使用任何文本编辑器查看与修改之,但须小心)中的数据库连接串应该具有类似如下内容(默认内容就是如此):

<connectionStrings> 
<add name="LocalSqlServer" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
</connectionStrings>
    当然,如果我们想使用自定义的数据库来存放用户信息,那么我们可以在本站点的web.config文件中<connectionStrings/>节添加自己的数据库连接串。为了简化起见,我们将使用默认数据库。
五、 创建受限目录

    为了区分已用户与匿名用户的访问权限,我们可以在此示例站点中创建某个受保护的目录,其中内容只能被登录用户访问(本示例中这个目录名为secured)。然后,在其中创建另一个ASP.NET页面Default.aspx(不同于系统自动生成的根目录下的那个)和另一个web.config文件。

【提示】你可直接把网站根目录下的两个相应文件复制到受限目录secured下,然后稍加修改。

   为了在阻止匿名用户访问该目录中页面的同时,允许登录用户访问,我们需要按如下所示修改此子目录下的web.config文件:
<?xml version="1.0"?> 
<configuration>
<system.web>
<authorization>
<deny users="?"/>
<allow users="*"/>
</authorization>
</system.web>
</configuration>
下面图1相应于受保护子目录下的Default.aspx页面屏幕快照(仅显示一句欢迎词)。


    图1.受保护子目录下页面屏幕快照

   上述配置之后,只有登录用户才能够访问到Secured/Default.aspx页面。若匿名用户尝试访问此页面,将被重定向到~/MyAjaxAuthenticationService.aspx页面处。

六、 创建一个示例用户

   为了下面试验的方便,现在我们要在网站存储配置信息的数据库aspnetdb.mdf中添加一个示例用户以用于测试示例程序的登录/注销功能。

   在Visual Studio中选择“网站→ASP.NET配置”菜单项,即可打开ASP.NET网站管理工具。在本示例中,我们要创建一个名字为“ABC”密码为“pass@word”的新帐户。为此,我们需要切换到该页面的“安全”选项卡并点击“创建用户”超级链接,将如图2所示。


    图2.使用ASP.NET网站管理工具创建新帐户

   输入以上信息及电子邮件信息,即可创建新帐户—ABC。此后,数据库aspnetdb.mdf中就加入了一个新帐户ABC。


七、 创建示例AJAX网站

    启动Visual Studio 2005,选择“文件→新建网站…”,然后选择“ASP.NET AJAX-Enabled Web Site”模板,命名工程为“AjaxAuthTest”,并选择C#作为内置支持语言,最后点击OK。注意,此后系统将自动加入对于程序集System.Web.Extensions.dll的引用(因其被自动加入到GAC中,所以默认情况下无法直接看到)。当然,你还会注意到,作为ASP.NET AJAX司令部的服务器控件ScriptManager被自动地添加到默认网页Default.aspx中。

   为了方便起见,我们直接把网页Default.aspx更名为本文中示例ASP.NET页面—MyAjaxAuthenticationService.aspx。下图3相应于这个页面的设计时刻屏幕快照。



    在用户初始进入到此页面(尚没有登录)时,显示“您已经注销了!”,而不显示“您已经登录了”的提示。此时,初始登录用户必须使用下面的两个文本框来输入用户名和密码信息,并提供了一个按钮“登录”,用于触发用户登录操作。下方的超级链接用于验证已经登录用户和匿名用户对于受保护子目录下网页default.aspx的访问权限。

    整个页面最下面的横线下面用于显示合法用法和非法用户登录过程中的一些信息,包括可能发生的异常。

八、 JavaScript编码部分

    分析完程序的用户接口部分,下面让我们开始JavaScript编码。
    右击示例网站添加一个JavaScript脚本文件,命名为Authentication.js。为了遵循模块化设计思想和有利于集中进行脚本调试,我们把所有有关JavaScript代码全部集中于此文件内。下面相应于这个文件的完整源码:
var usernameEntry;
//…………(省略)
var buttonLogout;

function pageLoad()
{
usernameEntry = $get("NameId");
passwordEntry = $get("PwdId");
username = $get("username");
password = $get("password");
textLoggedIn = $get("loggedin");
textNotLoggedIn = $get("notloggedin");
buttonLogin = $get("ButtonLogin");
buttonLogout = $get("ButtonLogout");
}

function SetDefaultLoginCompletedCallBack()
{
Sys.Services.AuthenticationService.set_defaultLoginCompletedCallback(OnLoginCompleted);
var callBack =
Sys.Services.AuthenticationService.get_defaultLoginCompletedCallback();
}
function SetDefaultLogoutCompletedCallBack()
{
Sys.Services.AuthenticationService.set_defaultLogoutCompletedCallback(OnLogoutCompleted);

var callBack =
Sys.Services.AuthenticationService.get_defaultLogoutCompletedCallback();
}
function SetDefaultFailedCallBack()
{
Sys.Services.AuthenticationService.set_defaultFailedCallback(OnFailed);
var callBack =
Sys.Services.AuthenticationService.get_defaultFailedCallback();
}

代码
function OnClickLogin() 
{
SetDefaultLoginCompletedCallBack();
SetDefaultLogoutCompletedCallBack();
SetDefaultFailedCallBack();
Sys.Services.AuthenticationService.login(username.value,
password.value, false,null,null,null,null,"User Context");
}
function OnClickLogout()
{
Sys.Services.AuthenticationService.logout(null,
null, null, null);
}
function OnFailed(error,
userContext, methodName)
{
DisplayInformation("error:message = " +
error.get_message());
DisplayInformation("error:timedOut = " +
error.get_timedOut());
DisplayInformation("error:statusCode = " +
error.get_statusCode());
}
function OnLoginCompleted(validCredentials,
userContext, methodName)
{
password.value = "";
if (validCredentials == true)
{
username.value = "";
buttonLogin.style.visibility = "hidden";
usernameEntry.style.visibility = "hidden";
passwordEntry.style.visibility = "hidden";
textNotLoggedIn.style.visibility = "hidden";
buttonLogout.style.visibility = "visible";
textLoggedIn.style.visibility = "visible";
DisplayInformation("");
}
else
{
textLoggedIn.style.visibility = "hidden";
textNotLoggedIn.style.visibility = "visible";
DisplayInformation(
"Login Credentials Invalid. Could not login");
}
}
function OnLogoutCompleted(result)
{
usernameEntry.style.visibility = "visible";
passwordEntry.style.visibility = "visible";
textNotLoggedIn.style.visibility = "visible";
buttonLogin.style.visibility = "visible";
buttonLogout.style.visibility = "hidden";
textLoggedIn.style.visibility = "hidden";
}
function DisplayInformation(text)
{
//…………(省略:负责在页面下方提示行是显示相应信息)
}
if (typeof(Sys) !== "undefined") Sys.Application.notifyScriptLoaded();
   有了上篇和前面的介绍,现在这段代码应该比较容易理解了。程序一开始创建几个全局变量。接下来是pageLoad()函数,这个函数将在客户端应用程序加载完毕后被ASP.NET AJAX客户端框架自动调用。在此函数中,我们仅为前面定义的几个全局变量关联上当前页面中的相应元素。
   再下来是我们使用上篇中建议的思路定义了几个常规回调函数SetDefaultLoginCompletedCallBack,SetDefaultLogoutCompletedCallBack和SetDefaultFailedCallBack,分别相应于登录完成后、注销完成后及前面两种情况下发生错误时要调用的回调函数。

   下面让我们简单地分析第一个回调函数的实现。
function SetDefaultLoginCompletedCallBack() 
{
Sys.Services.AuthenticationService.set_defaultLoginCompletedCallback(OnLoginCompleted);

var callBack = Sys.Services.AuthenticationService.get_defaultLoginCompletedCallback();
}
   第一句设置登录完成后要调用的回调函数——onLoginCompleted()。第二句作用是使用完回调函数最后进行简单“回收”,即清理掉前面的回调函数(置为null)。

   下面相应于回调函数onLoginCompleted的实现代码:
function OnLoginCompleted(validCredentials,
userContext, methodName)
{
password.value = "";
if (validCredentials == true)
{
username.value = "";
buttonLogin.style.visibility = "hidden";
usernameEntry.style.visibility = "hidden";
passwordEntry.style.visibility = "hidden";
textNotLoggedIn.style.visibility = "hidden";
buttonLogout.style.visibility = "visible";
textLoggedIn.style.visibility = "visible";
DisplayInformation("");
}
else
{
textLoggedIn.style.visibility = "hidden";
textNotLoggedIn.style.visibility = "visible";
DisplayInformation(
"Login Credentials Invalid. Could not login");
}
}
    在此回调函数中,首先把屏幕上的口令域清空。然后,判断是否浏览器中存在相应的表单认证cookie数据。有的话,则说明登录成功。接下来,把屏幕上的用户名域清空并隐藏掉刚才的登录信息,并显示已经成功登录的提示(绿字部分)。如果登录失败则显示红字部分的提示,并在下方提示行中显示登录失败信息。

   注销完成的回调函数与调用失败时的回调函数与此非常类似。在此,我们不再作分析。

  “登录”按钮的click事件处理器函数的代码如下所示:
function OnClickLogin()
{
SetDefaultLoginCompletedCallBack();
SetDefaultLogoutCompletedCallBack();
SetDefaultFailedCallBack();
Sys.Services.AuthenticationService.login(username.value,
password.value, true,null,null,null,null,"User Context");
}

 
   前面三句设置默认的回调函数。最后一句简单地调用AuthenticationService对象的login()方法,并将用户名和密码传递给服务器。注意第三个参数表示用户的登录信息将以Cookie的形式保存下来,即使关闭后重新打开一个浏览器窗口,同样也可以得到上次的登录信息。

   “注销”按钮的click事件处理函数的代码如下,其中调用了AuthenticationService对象的logout()方法,用来注销当前的用户:
function OnClickLogout() 
{
//清除掉表单认证cookie数据并实现注销
Sys.Services.AuthenticationService.logout(null,
null, null, null);
}
    由于我们在前面已经设定了AuthenticationService对象的3个默认回调函数,所以在调用login()和logout()方法返回之后,AuthenticationService对象将自动根据当前情况选择并调用上述3个回调函数中的某一个。

    到此为止,我们完成了整个示例程序的JavaScript代码编程部分。

九、 运行示例程序

    运行该示例程序,其初始界面将如图4所示。这时若是直接访问受保护的Secured目录,页面则被重定向回当前页面.


    图4.示例程序的初始界面

    输入用户名ABC,密码pass@word登录,可以看到程序即可以Ajax方式进行异步登录。登录后的界面如图5所示(注意最下面的提示信息)。此时若是点击“注销”按钮,当前的用户将被注销,程序也将返回至图4所示的界面。



    此时(尚未注销),如果点击下部的超级链接,则可以访问受保护的Secured目录中的Default.aspx页面,即可浏览到该页面的内容,如前面已经显示的图1所示。
0
相关文章