[翻译]开发自己的web站点管理工具(Website Administration Tool)(1)

原文地址:http://aspnet.4guysfromrolla.com/articles/052307-1.aspx
[原文源码下载]


[翻译]开发自己的web站点管理工具(Website Administration Tool)(1)


原文发布日期:2007.05.23
作者:Dan Clem
翻译:webabcd


介绍
基于Forms的验证,再结合ASP.NET 2.0的成员资格和角色管理系统,使得创建和管理用户账户变得相当地简单。 另外,还有一个让人感到非常爽的特性,就是与登录相关的web控件封装了大量的任务,这使得我们不用再像以前ASP那样手写很多代码。 本文用到了ASP.NET 2.0的成员资格和角色管理系统,你可以先参考一下Examining ASP.NET 2.0's Membership, Roles, and Profiles系列文章。

为了帮助你管理用户、角色和权限设置,ASP.NET 2.0包含了一个 Web Site Administration Tool (WSAT)。 你可以通过Visual Studio 2005的“网站”菜单下的“ASP.NET 配置”选项启动WSAT。 但是,WSAT只允许你管理本地的web站点。 当web站点部署在远程web主机上的时候,WSAT就会受到一些限制。 (WSAT的文件在“%WINDOWS%\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles”文件夹内,你可以在远程部署这个程序。)

与其把一个已有的WSAT搬到远程主机上,我觉得还是从零开始开发一个自己的WSAT更好一些。 我的版本除了具有WSAT的所有安全相关的特性外,还有一个十分有用的功能,就是“访问规则摘要”,你可以选择任何已有的用户或角色,然后就可以查看他们的目录树型权限视图。 你可以在本文的结尾处下载全部代码,然后就可以快速地将它部署到你的站点上。 本文从整体上讲述了我的自定义WSAT程序的实现,并且详细探讨了用户列表、添加用户和编辑用户的实现方法。在本系列文章的第二部分(译者注:中文在这里)中,将会详细地讲解我的自定义WSAT程序中的角色管理和访问规则的管理。 继续往下看,你会知道得更多!


使用我的自定义web站点管理工具(WSAT)
你可以在本文的结尾处下载我写的WSAT程序的全部代码。 其内包含有虚拟的企业内部网数据,可以用来演示程序的全部功能。 它的全局导航菜单为每一个部门(如IT、marketing、sales等)都提供了一个链接,而每个部门的web页分别存在于不同的文件夹内。 这个演示版使用的provider是SqlMembership,它存储用户信息在程序的App_Data文件夹内的ASPNETDB.MDF数据库。 该数据库是一个Microsoft SQL Server 2005 Express Edition数据库。

按如下的步骤做,你就可以运行这个程序了:
    1、复制所有内容到你机器的硬盘上,而且你的机器上一定要装有Visual Stuido 2005和SQL Server Express。 免费的Visual Web Developer也是可以的。
    2、打开Visual Studio。
    3、单击主菜单的“文件”“打开网站”,浏览我的自定义WSAT程序的目录,并打开web站点。
    4、单击工具栏上的绿色箭头开始调试。 Visual Studio就会启动它的内置web服务器,并在浏览器内显示登录页面。
    5、登录用户名为“Dan Clem”,密码“dan”。 Dan Clem是系统管理员。 你也可以用接下来的任何非管理员用户登录。 “Edward Eel”,“Frankin Forester”,“Gordy Gordon”,“Harold Houdini”,或者“Ike Iverson”。 每一个用户的密码就是其first name的小写。
    6、在全局导航菜单上单击“Admin”链接,你就可以看到程序的最主要的部分。 导航菜单上的其它链接分别指向我虚拟的企业内部网的各个部门的目录。 你可以在“访问规则管理”页和“访问规则摘要”页设置每个目录的访问权限。

如果你要把这个自定义的WSAT程序移植到你的已存在的并且使用了Memebership和Roles的程序中去的话,那么就需要完成如下步骤:
    1、复制admin文件夹到你的ASP.NET程序的根目录下。 (在我的程序里,我把admin文件夹放到了web站点的根目录下,不过如果将其放到ASP.NET程序下的某个子文件夹内也是可以正常工作的)
    2、复制Alphalinks用户控件(alphalinks.ascx)到你web站点的一个合适的目录内,然后修改users.aspx页的@Register指令,使其匹配新的地址。 (关于用户控件是如何工作的更详细的说明,可以参看An Extensive Examination of User Controls
    3、复制i目录下的图片文件到你程序的一个合适的文件夹内,然后修改access_rules.aspx页和access_rule_summary.aspx页内的图片链接地址。
    4、在你的程序根目录下的web.config文件内的system.web节点下注册如下命名空间。 它们是程序里的一些web页需要用到的命名空间,如使用DataTable类和DirectoryInfo类的时候。
<pages>
   
<namespaces>
      
<add namespace="System.Data" />
      
<add namespace="System.IO"/>
   
</namespaces>
</pages>
    5、要修改导航菜单样式的话,应该在母版页中修改。 (我既用到了ASP.NET 2.0中的方法,又用到了传统的ASP方法。例如,全局导航菜单我写到了母版页里,Admin下的导航菜单我写到了一个文件里,需要用到它的页会把它include进来)
    6、注意,admin文件夹下有两个子文件夹: access和activity。 我的WSAT程序的全部功能都包含在access文件夹内。 增加activity文件夹的作用是,我想在这里增加日志功能。
    7、我们需要给admin文件夹增加权限配置,以使允许的角色或用户才能使用这个功能,后面我们会详细说到。

如果你已经下载了这个程序,并且已经安装了,那么通过本文接下来的内容,你就会了解如何添加用户、编辑用户,以及如何使用用户列表。 本系列文章的第二部分(译者注:中文在这里)主要用于讲解角色管理和访问规则的实现。 本文和下一篇文章所带来的东东,可以作为你管理权限的一个非常好的工具。


管理用户帐号
官方的ASP.NET 2.0 WSAT程序提供了一套用于管理web站点的用户、角色和访问规则的页面。 而在我开发的这个自定义WSAT程序中,除了保留所有原WSAT的核心功能外, 还增加了一个非常拥有的功能,即“访问规则摘要”,它可以非常方便地查看到每个角色或用户对站点内每个目录和文件的访问权限。 我开发了一套用户列表页面,它具有我们平时常用的功能。 具体如下:
    ·按用户名搜索用户
    ·按角色名搜索用户
    ·可用用户
    ·在线用户
    ·被锁定的用户

下面的截屏就展示了这些功能。 这个GridView用于显示web站点的用户及其详细信息。 GridView上面的一排连接允许你按用户搜索,或者角色搜索,又或者仅仅查找可用用户、在线用户或被锁定的用户。 而“User Name filter”可以让你通过用户名的首字母进行搜索。



按用户名搜索用户
通过用户名查找用户就是靠下面两行代码实现的:
Users.DataSource = Membership.GetAllUsers();
Users.DataBind();

.NET框架内的Membership类有一个用来检索所有用户信息的方法,就是GetAllUsers()方法,它会返回站点的所有用户。

我想在WSAT程序里增加一个按用户名首字母搜索用户的功能, 所以我决定创建一个ASP.NET用户控件,稍后我会用到它。 因为我是刚刚才学的如何创建ASP.NET用户控件,所以完成它比我计划的花了更多的时间,但从中我也学到了很多东西,现在我就来和大家分享一下。 我把这个控件称作“Alphalinks”,一共开发了两个版本。 第一个版中本我用的是传统的ASP的方法,也就是基于QueryString的导航。 控件会把首字母以QueryString的形式加到链接上,就像这样:&letter=X。

之后的第二个版本里,我就跟基于QueryString的导航方式说再见了,而是使用一个有合适的postback的用户控件做导航。 而且,我很快就意识到了这样使用的好处。 也就是我们可以通过属性的方式访问控件的值,这要优于使用传统的ASP方式的Request.QueryString。 详细点说,就是我给Alphalinks控件增加了一个Letter属性,它可以返回被选择的字母。 增加了这个属性后,这个控件就可以像下面这样使用了:
Users.DataSource = Membership.FindUsersByName(Alphalinks.Letter + "%"); 


按角色名搜索用户
按角色名搜索用户的功能是使用一个GridView来展现的,它会显示出你指定的角色下的所有用户。 在这里我使用了一个DropDownList来代替Alphalinks控件,这个DropDownList会列出系统内的所有角色。 DropDownList所绑定的数据就是用Roles类的GetAllRoles()方法所取得的数据,如下所示:
UserRoles.DataSource = Roles.GetAllRoles();
UserRoles.DataBind(); 

接下来的逻辑有些复杂,因为Membership和Roles都没有给我们提供通过角色返回所有用户的详细信息的方法。 虽然Roles类有一个GetUserInRole(roleName)的方法,但是它返回的只是你指定的角色下的所有用户的用户名,而没有用户的如email、状态、最后登录日期之类的详细信息。 没有现成的方法,我就自己写一些代码来返回指定角色下的所有用户的详细信息。 我先把指定角色下的用户名全部取出,然后再根据用户名把相应的用户的详细信息添加到一个集合中。
// 获取所有用户
MembershipUserCollection allUsers = Membership.GetAllUsers();
MembershipUserCollection filteredUsers 
= new MembershipUserCollection();

if (UserRoles.SelectedIndex > 0)
{
   
// 得到指定角色下的用户名
   string[] usersInRole = Roles.GetUsersInRole(UserRoles.SelectedValue);
   
   
// 将指定角色下的所有用户的详细信息添加到filteredUsers
   foreach (MembershipUser user in allUsers)
   
{
      
foreach (string userInRole in usersInRole)
      
{
         
if (userInRole == user.UserName)
         
{
            filteredUsers.Add(user);
            
break
         }

      }

   }

}

else
{
   filteredUsers 
= allUsers;
}


// 绑定用户信息到GridView
Users.DataSource = filteredUsers;
Users.DataBind(); 

最后的3个页(可用用户、在线用户、被锁定的用户)都比较简单。 它们都是先通过Membership.GetAllUsers()方法来得到所有用户,然后再根据MembershipUser对象的某个属性来判断是否要把该用户添加到一个MembershipUserCollection集合里。 最后再把这个集合绑定到GridView,并显示在页面上。 注意:可用用户对应的是MembershipUser类的IsApproved属性,在线用户对应的是IsOnline属性,被锁定用户对应的是IsLockedOut属性。


另一种筛选用户的方法
如果要筛选用户,一般我们都会使用上面所述的逻辑。 首先通过Membership.GetAllUsers()获得所有用户,然后再根据条件筛选,把需要的用户添加到一个集合里。 但是,如果有大量用户的话,就不适合用这个方法了。 如果你的系统可能用数百个以上的用户,那么就应该考虑放弃用这个方法,而是使用更高效的技术了。

例如,如果你使用的是SqlMembershipProvider的话,那么就应该在在数据库中添加一个存储过程以返回筛选后的用户信息,存储过程要做的工作就是关联aspnet_Users、aspnet_Membership、aspnet_Roles和aspnet_UsersInRoles,然后按条件筛选数据。 同样地,你还应该使用自定义分页逻辑来高效地返回指定的数据给GridView(参看Custom Paging in ASP.NET 2.0 with SQL Server 2005)。
 

创建新的用户
通过Membership类的CreateUser()方法可以很方便地新建用户。 我的这个WSAT程序里包含一个“新建用户”页,其内有一个CheckBoxList控件,用于让你选择用户所属的角色身份。

在设计Membership系统的时候,微软决定只封装用户的核心信息,如用户名、密码和最后登录日期之类的。 如果我们需要在程序里增加用户的其他信息的话,如性别、地址和生日之类的,那么我们可以使用Profile系统或者开发自己的一套管理用户其他信息的逻辑。关于ASP.NET 2.0的Profile系统可以参看Profiles in ASP.NET 2.0。要在自定义表里保存用户的其他信息的话可以参看Customizing the CreateUserWizard Control

下面就是“新建用户”页的截屏:


实现新建用户功能的代码非常简单: 下面例子中的第一行用于添加用户;第二行用于添加备注(因为CreateUser这个方法里没有“备注”这个参数)。 成功添加用户之后,通过foreach循环CheckBoxList的各项,然后再给新建的用户添加相关的角色。
protected void AddUser()
{
   
// 添加用户
   MembershipUser newUser = Membership.CreateUser(username.Text, password.Text, email.Text);
   newUser.Comment 
= comment.Text;
   Membership.UpdateUser(newUser);
   
   
// 添加角色
   foreach (ListItem rolebox in UserRoles.Items)
   
{
      
if (rolebox.Selected)
      
{
         Roles.AddUserToRole(username.Text, rolebox.Text);
      }

   }

}
 


编辑已有用户
“编辑用户”页和“新建用户”页差不多,你可以通过用户信息列表页的链接访问到“编辑用户”页。 在这个页中我使用CheckBoxList来编辑用户所属角色,用DetailsView来显示用户的信息。 因为CheckBoxList与DetailsView是两个控件,所以我必须手动地设置复选框的状态,以使CheckBoxList和DetailsView保持信息上的同步。
private void Page_PreRender()
{
   
// 让CheckBoxList绑定所有角色
   UserRoles.DataSource = Roles.GetAllRoles();
   UserRoles.DataBind();

   
// 如果不是编辑状态,则所有复选框都应该是不可用的状态
   if (UserInfo.CurrentMode != DetailsViewMode.Edit)
   
{
      
foreach (ListItem checkbox in UserRoles.Items)
      
{
         checkbox.Enabled 
= false;
      }

   }

   
   
// 如果用户属于某个角色,则勾选相应的复选框
   string[] userRoles = Roles.GetRolesForUser(username);
   
foreach (string role in userRoles)
   
{
      ListItem checkbox 
= UserRoles.Items.FindByValue(role);
      checkbox.Selected 
= true;
   }

}
 

另外,我还写了一些用于从角色中添加或移除用户的代码,这是必需的。 这段代码将在DetailsView的OnItemUpdating事件中被调用。
private void UpdateUserRoles()
{
   
foreach (ListItem rolebox in UserRoles.Items)
   
{
      
if (rolebox.Selected)
      
{
         
if (!Roles.IsUserInRole(username, rolebox.Text))
         
{
            Roles.AddUserToRole(username, rolebox.Text);
         }

      }

      
else
      
{
         
if (Roles.IsUserInRole(username, rolebox.Text))
         
{
            Roles.RemoveUserFromRole(username, rolebox.Text);
         }

      }

   }

}
 


结论
本文从整体上讲述了我的自定义WSAT程序的实现(本文结尾处你可以下载到这个程序),并且详细探讨了用户列表、添加用户和编辑用户的实现方法。 关于角色管理和访问规则的管理请参看本系列文章的第二部分(译者注:中文在这里)。


到这里本文结束。 祝编程愉快!
posted @ 2007-06-10 18:33  webabcd  阅读(8667)  评论(12编辑  收藏  举报