客户端应用程序服务演练
使用 ASP.NET 成员资格提供程序在 Windows 应用程序中设置客户端应用程序服务以进行用户登录的演练

引言
许多分布式应用程序都需要用户验证功能。当然,有许多方法可以为智能客户端、离线或 ClickOnce 应用程序创建自己的身份验证机制。然而,Microsoft 为 ASP.NET 2.0 引入了成员资格和角色提供程序,这在某些场景下对于可互换的安全机制来说是流行且有用的。不幸的是,这些提供程序在 Windows 客户端应用程序中并未得到官方支持。有些人找到了变通方法,但现在随着 .NET 3.5 和 Visual Studio 2008 的推出,成员资格提供程序得到了官方支持并集成到架构中。
这是一个示例演练,说明如何使 .NET 3.5 Windows 应用程序利用 ASP.NET 成员资格和角色提供程序服务,这项功能现在被称为客户端应用程序服务。为了我们的目的,我将使用 SQL Server 提供程序,以实现快速和易于设置,但任何提供程序都将有效(尽管创建自定义提供程序超出了本教程的范围)。需要了解的术语
- 提供程序:一种可插拔结构,可以使用任何符合提供程序接口的对象
- 成员资格提供程序:用户存储和管理
- 角色提供程序:访问规则存储和管理
整个解决方案将涉及一个 SQL Server 数据库、一个 ASP.NET Web 应用程序(带 AJAX)和一个 Windows 应用程序。数据库将存储用户和访问规则。Web 应用程序将通过提供程序接口(并通过数据库)公开 AJAX 服务,用于身份验证和授权用户。Windows 应用程序将使用 Web 应用程序进行身份验证和授权。
第一阶段
对于第一阶段,我们将处理数据库。识别或创建一个目标数据库来存储用户和角色信息。请注意,这不适用于用户实例附加数据库(例如您在 *App_Data* 文件夹中放置的数据库)。您需要实际在某个 SQL Server 实例上创建数据库。据我所知,SQL 2000 或 SQL 2005 都可以。
运行 *C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regsql.exe* 以创建 SQLProvider 表、视图和存储过程。是的,这在 *v2* 文件夹中。您可以双击可执行文件来启动它,它会启动一个控制台窗口,然后是一个小的向导 GUI。按照向导步骤在目标数据库中创建对象。您还可以使用此实用程序从给定数据库中删除这些表、视图和存储过程。对象的名称中将包含“aspnet”。完成此操作后,尝试打开数据库并检查为您生成的表、视图和存储过程的数量。
第二阶段
现在进入第二阶段,让我们创建一个可以用于授权和身份验证的网站。创建一个新的网站或 Web 应用程序项目。确保它已“启用 AJAX”。在 Visual Studio 2008 中,这是默认设置。实际上,您可以删除 *Default.aspx*,因为本教程不会使用它。如果 *App_Data* 存在,也可以删除它。打开 *web.config* 并准备配置成员资格提供程序。这需要四个步骤。
添加一个连接字符串到之前创建和配置的数据库。请注意,连接字符串的名称很重要,将在下一步中使用。例如,我在 SQL 2005 中对名为 CASExample 的数据库使用了 *aspnet_Regsql*。然后我分离了它,并将 MDF 文件复制到网站的 *App_Data* 文件夹。这使得我能够轻松地分发代码以用于教程目的。通常,我不使用 *App_Data* 文件夹,而是更喜欢服务器上的数据库实例。您可以采用对您来说最舒适的方法。我还使用 clear 标签清除了连接字符串集合,因为有一个连接字符串继承自 *machine.config*,我不喜欢它。
<connectionStrings>
<!-- sqlexpress connection string can attach the db
in app_data folder which already has the aspnet tables in it. -->
<add name="casExampleConnectionString"
connectionString=
"data source=.\SQLEXPRESS;Integrated Security=SSPI;" +
"AttachDBFilename=|DataDirectory|CASExample_data.mdf;User Instance=true"
providerName="System.Data.SqlClient"/>
<!-- if you do not have sqlexpress installed,
manually attach the mdf file (or use the db backup to restore)
and use this conn string syntax instead -->
<!-- add name="casExampleConnectionString"
connectionString=
"server=.\sql2005;database=CASExample;uid=sa;pwd=PASSWORD"
providerName="System.Data.SqlClient" /-->
</connectionStrings>
然后配置应用程序以使用表单身份验证从浏览器收集用户登录信息(这在 *system.web* 下)。请注意,这将设置表单身份验证,但不会限制对网站或其任何内容的访问。这只是设置网站,以便在请求或使用身份验证时使用表单身份验证。
<authentication mode="Forms" />
接下来,在 *system.web* 中添加一个成员资格块,以配置应用程序使用 SQL 数据库进行成员资格。这些是您使用成员资格所需设置的最小设置。还有许多其他关于密码强度等的设置。请注意,*machine.config* 中定义了一个默认成员资格提供程序,它会尝试连接到您的 *App_Data* 文件夹中名为 *aspnetdb.mdf* 的数据库。这让我很恼火,所以我使用一个 `<clear />` 元素清除了现有提供程序。
<membership defaultProvider="casExampleSqlProvider">
<providers>
<clear />
<add name="casExampleSqlProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="casExampleConnectionString"
applicationName="CASExample" />
</providers>
</membership>
MSDN 上有更多关于成员资格提供程序的信息。现在,向 *system.web* 添加一个角色管理器块,以配置应用程序使用 SQL 数据库进行角色管理。与成员资格块一样,还有其他设置,但这些是最小设置。clear 块也删除了 *machine.config* 定义的提供程序。
<roleManager enabled="true" defaultProvider="casExampleSqlRoleProvider">
<providers>
<clear />
<add name="casExampleSqlRoleProvider"
connectionStringName="casExampleConnectionString"
applicationName="CASExample"
type="System.Web.Security.SqlRoleProvider" />
</providers>
</roleManager>
MSDN 提供了更多关于roleManager 提供程序的信息。至此,网站已配置为使用成员资格和角色。如果您对创建“安全”网站感兴趣,那么您现在就可以开始。但是,Windows 应用程序将无法直接利用成员资格和角色服务。为此,您必须通过 AJAX 公开服务。谢天谢地,这非常简单。将此添加到 *web.config*(如果您已经有一个 system.web.extensions
部分,请将其组合起来)。
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true" />
<roleService enabled="true"/>
</webServices>
</scripting>
</system.web.extensions>
MSDN 有一个完整的 AJAX 示例,您可以在网页中使用 JS 客户端脚本调用身份验证服务。回顾该页面上的示例 JavaScript 显示,ASP.NET AJAX 引擎会自动为我们创建一个 Sys.Services.AuthenticationService
对象。我们对 Windows 客户端应用程序感兴趣,因此我们将跳过此示例。
现在,我们的系统中至少需要一个用户和一个角色。创建这些的最快方法是使用通过 Visual Studio 提供的 ASP.NET 网站管理工具。这绝对不是管理用户和角色的最佳方法,也不是首选方法,但对于教程来说它会有效。在 Visual Studio 中,确保已选择网站,然后转到“网站”>“ASP.NET 配置”。这将启动 ASP.NET 配置网站。另外,Visual Studio 2008 似乎不像 Visual Studio 2005 那样会破坏 *web.config*。
单击“安全”选项卡,创建两个角色:Admin 和 User。另外创建两个用户,每个角色中一个。我们稍后将需要这些用户来测试 Windows 应用程序。在我的示例数据库中,用户是
- 用户名:admin 密码:admin!!
- 用户名:user 密码:user!!!
第三阶段
继续第三阶段,我们创建一个 Windows 应用程序。使用默认设置创建一个 Windows 窗体应用程序。为了方便起见,将其添加到与 Web 应用程序相同的解决方案中。打开项目属性窗口。切换到“服务”选项卡。选中“启用客户端应用程序服务”复选框。确保选中“表单身份验证”单选按钮。输入解决方案中 Web 应用程序的基 URL——不带页面名称。在我的示例中,URL 是 *https://:2539/Web*。也在“角色服务位置”框中输入此 URL。
让我们了解一下幕后发生了什么。打开 *app.config*。请注意,它已为客户端应用程序服务添加了一个配置部分,其中包含两个对应于成员资格和角色的节点。还请注意,这些节点在设置中嵌入了 URL,这在部署期间更改非常重要(提示)。还要注意,它有一个用于服务 URL 的 appSettings
条目,该条目为空白。如果您使用配置文件服务,这将是配置文件服务的条目。还要注意,这些 URL 已将“文件名”附加到名为 *Authentication_JSON_AppService.axd* 和 *Role_JSON_AppService.axd* 的虚拟文件。对这些“页面”(以及其他 * .axd* 文件)的请求由 ASP.NET 引擎解释并路由到相应的 HTTP 处理程序。这在需要时支持脚本文件,非常类似于 AJAX 工具包和扩展器中的其他项目。显然,当我们向 *web.config* 添加正确的节点时,.NET 会创建这些特定的文件。
如果您还没有足够多的 Microsoft 生成的文件,我们刚刚将魔法变成了 Microsoft 生成的文件。不过,AJAX 和自定义 HTTP 处理程序超出了本教程的范围,因此此时请随意关闭 *app.config*。
在 Windows 应用程序中,添加对 *System.Web* 的引用。将 Form1
重命名为 LoginForm
。添加两个文本框,命名为 txtUsername
和 txtPassword
,以及一个按钮,命名为 btnLogin
。将 txtPassword
的 UseSystemPasswordChar
属性值设置为 true
。将 btnLogin
设置为窗体的 AcceptButton
。
添加第二个窗体,命名为 MainForm
。在上面放置一个菜单条。添加两个顶级菜单项,一个文本为“Admin menu”,另一个文本为“User menu”。为每个顶级菜单项添加一些子项。Visual Studio 应该将这两个顶级菜单项命名为 adminMenuToolStripMenuItem
和 userMenuToolStripMenuItem
。如果不是,请记住它们的名称。
打开 *Program.cs*。main 方法中的最后一行应该是 Application.Run(new LoginForm());
。将其替换为以下代码块
ApplicationContext _applicationContext = new ApplicationContext();
LoginForm login = new LoginForm();
if (login.ShowDialog() == DialogResult.Yes)
{
MainForm m = new MainForm();
m.Show();
Application.DoEvents();
Application.Run(_applicationContext);
}
else
{
Application.Exit();
}
这将在应用程序启动时启动登录窗体,并查找它返回 DialogResult
的 Yes
值。如果返回 Yes
,应用程序将启动主窗体并将其控制权传递给它。否则,应用程序退出。有关此方法的更多详细信息,请参阅 Omar Al Zabir 在 Code Project 上发表的文章 使用 .NET 2.0 开发下一代智能客户端并使用现有的 .NET 1.1 基于 SOA 的 XML Web 服务。转到 LoginForm
的设计视图。双击 btnLogin
并将以下代码添加到其单击事件处理程序中。
bool isValid =
System.Web.Security.Membership.ValidateUser(txtUsername.Text, txtPassword.Text);
if (isValid)
{
this.DialogResult = DialogResult.Yes;
}
else
{
MessageBox.Show("Login unsuccessful.");
this.DialogResult = DialogResult.None;
}
第一行使用内置的 ASP.NET 成员资格验证用户凭据。如果成功,窗体的 DialogResult
设置为 Yes
,这是我们的 *Program.cs* 期望的成功值。否则,会显示一条消息,表示登录不成功,并且 DialogResult
设置为 None
,这将导致 *Program.cs* 退出。显然,这段代码需要错误处理,并且可以改进以允许用户多次尝试凭据。在设计器中打开 MainForm
。为 Closed
事件添加一个事件处理程序,并将此代码放入处理程序中
Application.Exit();
最后一步是向 MainForm
添加一些角色处理。创建一个 Load
事件处理程序,并将此代码放入处理程序中
adminMenuToolStripMenuItem.Visible =
System.Threading.Thread.CurrentPrincipal.IsInRole("Admin");
如果登录用户不在管理员角色中,这将隐藏管理员菜单控件。显然,这可以重构并更好地处理,但它传达了要点。
结论
我们现在拥有一个使用 ASP.NET 成员资格和角色服务的端到端 Windows 客户端。将客户端程序设置为解决方案中的启动项目并运行它。您应该能够以任一角色的用户身份登录,此外,您应该只看到与您的登录角色相对应的菜单控件。有关完整示例,请参阅代码示例。
有用的链接
- 比 MSDN 帮助文档中任何演练都更完整的完整演练
- 客户端应用程序服务
- ASP.NET 应用程序服务
- ASP.NET AJAX 应用程序服务示例
- 为客户端应用程序服务配置 Windows 应用程序
- 配置成员资格节点
- 配置 roleManager 节点
- Peter Kellner 的 Web 用户管理控件
- 我所知的唯一商业会员管理控件
历史
- 2007 年 12 月 7 日 -- 原始版本发布