创建自定义Membership提供器

2.3.7 创建自定义Membership提供器
由于ASP.NET Membership使用提供器模式,所以可以很容易的通过创建自定义Membership提供器来对ASP.NET Membership进行扩展。这里主要有两类需要创建自定义Membership提供器的情形。
第一类,假设你已经拥有了一个ASP.NET 1.x或传统ASP实现的应用程序。并且当前的成员信息保存在完全自定义的数据库表结构中。此外,该数据库的表结构很难和SqlMembershipProvider所使用的数据库表结构进行映射关联。
在这种情况下,创建自定义Membership提供器来读取已有的数据库表结构是很有意义的。创建了这样的自定义Membership提供器后,就可以在已有数据库表结构上使用ASP.NET Membership。
第二类,假设你需要将用户信息保存在除了微软SQL Server数据库或活动目录服务器端以外的其他数据存储环境中。例如,有些公司或组织可能是会使用Oracle或DB2这类数据库服务器端。这样一来,就需要创建自定义Membership提供器来访问自定义的数据存储环境。
在本节中,我们会创建一个简单的自定义Membership提供器:将用户信息保存在XML文档中的XmlMembershipProvider。
不幸的是,如果将实现XmlMembershipProvider的所有代码都放在这里将会太占篇幅。不过这些代码已放置在本书随书附带资源中,该代码文件名为XmlMembershipProvider.cs,并位于App_Code文件夹中。
XmlMembershipProvider类继承至MembershipProvider抽象类。该抽象类提供了超过25个属性和方法需要实现。
例如,ValidateUser()方法需要被实现。因为Login控件在对用户名和密码进行校验时需要调用这个方法。
CreateUser()方法也需要被实现。当CreateUserWizard控件创建新用户时会调用这个方法。
用来配置XmlMembershipProvider的Web配置文件包含在代码清单2-25中。
代码清单2-25 Web.Config
<?xml version="1.0"?>
<configuration>
    <system.web>
      <authentication mode="Forms" />
     
      <membership defaultProvider="MyMembershipProvider">
        <providers>
          <add
            name="MyMembershipProvider"
            type="AspNetUnleashed.XmlMembershipProvider"
            dataFile="~/App_Data/Membership.xml"
            requiresQuestionAndAnswer="false"
            enablePasswordRetrieval="true"
            enablePasswordReset="true"
            passwordFormat="Clear" />   
        </providers>
      </membership>
     
    </system.web>
</configuration>
需要注意的是XmlMembershipProvider支持许多的属性。例如,它支持passwordFormat属性,该属性用于指定密码是以散列值形式还是以明文形式保存(该属性不支持对密码进行加密设置)。
该XmlMembershipProvider提供器将成员信息保存在一个名为Membership.xml的XML文件中,且该文件位于App_Data文件夹。如果需要,也可以手动将用户添加到该文件中。另外,还可以通过CreateUserWizard控件或Web站点管理工具来创建新用户。
代码清单2-26中包含了一个Membership.xml文件的示例。
代码清单2-26 App_Data\Membership.xml
<credentials>
<user name="Steve" password="apple" email="steve@somewhere.com" />
<user name="Andrew" password="secret" email="andrew@somewhere.com" />
</credentials>
在随书资源提供的示例代码中,包括了一个Register.aspx页面、一个Login.aspx页面和一个ChangePassword.aspx页面。通过使用这些页面,可以对XmlMembershipProvider所提供的各种功能进行方便的试验。
注意   动态XPath查询可能会带来XPath注入攻击,就像动态SQL查询可能会带来SQL注入攻击一样。在编写XmlMembershipProvider类时,我们应该尽量避免使用诸如SelectSingleNode()这样的方法来避免XPath注入攻击,即时使用这些方法可能会得到更简单和高效的代码。但大多数时候,代码的安全性比快速开发和运行更为重要。
我们可以通过将用户分组到角色中,再将授权设置应用到相应角色上,以代替为单个用户分别进行授权设置。例如,我们可以对应用程序站点的某一部分内容进行密码鉴别保护,以确保只有管理员角色中的成员可以访问这些部分中的页面。
类似于ASP.NET Membership,角色管理器已经内建在当前的ASP.NET鉴别框架中。可以通过向一个或多个Web配置文件中添加authorization节点来配置角色鉴别规则。
此外,类似ASP.NET Membership,角色管理器也是使用的提供器模式。我们可以通过配置特定Role提供器来自定义角色信息保存在什么地方。
ASP.NET Framework提供了三个角色提供器:
q SqlRoleProvider——用于将角色信息保存在微软SQL Server数据库中;
q WindowsTokenRoleProvider——使用微软Windows用户组设置来表示角色信息;
q AuthorizationStoreRoleProvider——使用授权管理器将角色信息保存在诸如XML文件、活动目录或ADAM中。
在接下来的小节中,将会介绍如何配置每个Role提供器。还会介绍如何通编程方式来调用角色API,从而管理角色信息。
2.4.1 配置SqlRoleProvider
SqlRoleProvider是默认的角色提供器。使用SqlRoleProvider可以将角色信息保存到微软SQL Server数据库中。利用SqlRoleProvider可以创建自定义角色,所以你可以创建任何需要的角色。
SqlRoleProvider可以用于Forms鉴别和Windows鉴别中。当启用Forms鉴别后,就可以使用ASP.NET Membership来表示用户并把用户分派到特定的角色上。当启用Windows鉴别后,特定的Windows账号将被指派到自定义角色上。在这一节中,我们假设示例应用程序使用的是Forms鉴别。
注意   在启用Windows鉴别时,Web站点管理工具不支持将用户指派到角色上。所以在Windows鉴别被启用后,必须通过编程的方式来将用户指派到角色上。
代码清单2-27中的Web配置文件启用了SqlRoleProvider。
代码清单2-27 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
    <roleManager enabled="true" />
    <authentication mode="Forms" />
</system.web>
</configuration>
角色管理在默认情况下是禁用了的。代码清单2-27中的配置文件简单的启用了角色管理器。需要注意的是该配置文件同时还启用了Forms鉴别。
如果你不想自己编写代码清单2-27中的文件内容,那么你可以使用Web站点管理工具来创建它们。通过选取Visual Web Developer中的菜单选项:WebSite(站点)→ASP.NET Configuration(ASP.NET配置),从而打开Web站点管理工具。接下来,点击安全选项卡和启用角色连接(见图2-11)。
当启用了角色管理器后,还需要创建一些角色。我们有两种方法来创建角色。一是使用Web站点管理工具,或使用编程方式创建角色。
开启Web站点管理工具,并点击位于安全选项卡下的创建或管理角色连接。这样就可以开始进行角色创建了。我们假定你已经创建了一个名为Manager的角色。
当创建了一批角色后,还需要将用户指派到相应的角色中。同样,也可以使用Web站点管理工具来完成这个任务,或使用编程方式来做。
如果你的应用程序中还未曾创建任何用户,那么可以立即通过点击安全选项卡下的创建用户连接来创建新用户。需要注意的是在创建用户的同时,可以将该用户指派到一个或多个角色中(见图2-12)。也可以在随后的操作中,再通过点击创建或管理角色连接来为用户指派相应角色。

图2-11 通过Web站点管理工具启用角色
图2-12 为新用户指派角色

当创建好角色并将用户指派到这些角色上后,就可以在Web配置文件的authentication节点中使用这些角色了。例如,假设你的Web站点包含了一个名为SecretFiles的文件夹,并且你只希望属于Manager角色中的成员能访问该文件夹下的页面。代码清单2-28中的Web配置文件,会阻止除了属于Manager角色中的成员以外的任何用户访问SecretFiles文件夹。
代码清单2-28 Web.Config
<?xml version="1.0"?>
<configuration>
<system.web>
    <authorization>
      <allow roles="Managers"/>
      <deny users="*"/>
    </authorization>
</system.web>
</configuration>
代码清单2-28中的配置文件授予角色Managers对该目录有访问权限,并同时限制了除此角色以外的其他所有用户对该目录的访问权限。
如果你喜欢,也可以通过Web站点管理工具来管理授权。在后台,该工具会自动创建一个包含了authorization节点的Web配置文件(换句话说,该工具将完成我们之前刚做过的所有配置工作)。
在“安全”选项卡中,点击“创建访问规则连接”。从树视图中选中SecretFiles文件夹,再选择Managers角色并选中Allow(允许)选项(见图2-13)。点击确定按钮即会授权该角色的访问权限。接下来,再创建禁止非Managers角色访问用户信息的第二个授权。选择SecretFiles文件夹、选择All Users再选择Deny。点击确定按钮即添加新的权限授权。
通过SqlRoleProvider使用不同的数据库
在默认情况下,SqlRoleProvider同样是使用微软SQL Server精简版来作为ASP.NET Membership的数据库:AspNETDB.mdf。在应用程序根目录下的App_Data文件夹中会自动创建系统需要的数据库。
图2-13 为角色设置权限授权
如果要将角色信息保存到其他的微软SQL Server数据库中,那么必须要执行以下两个配置步骤:
q 配置数据库以使其包含必须的数据库对象;
q 配置应用程序以使其使用新的数据库。
在将角色信息保存到数据库中之前,还需要将必要的表和存储过程添加到数据库中。添加这些对象的最简单方法是使用aspnet_regsql命令行工具。该工具位于系统的下列目录中:
\WINDOWS\Microsoft.NET\Framework\[version]
注解   如果使用SDK中提供的命令行工具,则可以直接执行该命令,而不再需要通过命令行命令进入Microsoft.NET文件夹。
如果不带参数运行aspnet_regsql命令,那么ASP.NET SQL Server数据库安装向导将被打开(见图2-14)。我们也可以使用这个向导来连接到数据库,并自动地添加数据库对象。
图2-14 使用SQL Server数据库安装向导
另外,还可以通过执行下列两个SQL批处理文件来设置数据库。
q InstallCommon.sql
q InstallRoles.sql
以上批处理文件和aspnet_regsql工具位于同一文件夹中。
当安装完数据库对象后,还需要配置一个包含正确连接字符串的新SqlRoleProvider。代码清单2-29中的Web配置文件配置了一个名为MyRoleProvider的新提供器,以用来连接到MyServer服务器端中名为MyDatabase的数据库上。
代码清单2-29 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
    <add
      name="MyConnection"
      connectionString="Data Source=MyServer;Integrated Security=True;Initial Catalog=MyDatabase"/>
</connectionStrings>
<system.web>
    <authentication mode="Forms" />
    <roleManager enabled="true" defaultProvider="MyRoleProvider">
      <providers>
        <add
          name="MyRoleProvider"
          type="System.Web.Security.SqlRoleProvider"
          connectionStringName="MyConnection"/>
      </providers>
    </roleManager>
</system.web>
</configuration>
代码清单2-29中的配置文件创建了一个名为MyRoleProvider的默认RoleManager。需要注意的是,MyRoleProvider提供器包含了指向MyConnection连接的connectionStringName属性。
2.4.2 配置WindowsTokenRoleProvider
当使用WindowsTokenRoleProvider提供器时,角色这个概念相当于微软Windows用户组。在使用WindowsTokenRoleProvider时,必须要启用Windows鉴别。而不能在WindowsTokenRoleProvider中使用Forms鉴别和ASP.NET Membership。
代码清单2-30中的配置文件将WindowsTokenRoleProvider配置为了默认的提供器。
代码清单2-30 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
    <authentication mode="Windows" />
    <roleManager enabled="true" defaultProvider="MyRoleProvider">
      <providers>
        <add
          name="MyRoleProvider"
          type="System.Web.Security.WindowsTokenRoleProvider" />
      </providers>
    </roleManager>
</system.web>
</configuration>
代码清单2-31中的页面包含了一个LoginView控件。LoginView控件将为Windows管理员组中的成员显示相对其他成员不同的内容(见图2-15)。
代码清单2-31 ShowWindowsRoles.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Windows Roles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
   
    <asp:LoginView
        id="LoginView1"
        Runat="server">
        <RoleGroups>
        <asp:RoleGroup Roles="BUILTIN\Administrators">
            <ContentTemplate>
            <h1>Welcome Administrator!</h1>      
            </ContentTemplate>
        </asp:RoleGroup>
        </RoleGroups>
        <LoggedInTemplate>
            <h1>Welcome Average User!</h1>
        </LoggedInTemplate>
    </asp:LoginView>
   
    </div>
    </form>
</body>
</html>
图2-15 为Windows管理员组中的成员显示不同的内容
如果在启用了WindowsTokenRoleProvider后访问代码清单2-31中的页面,那么只有当用户是Windows管理员组中的成员时,才能看到上图中的内容。
2.4.3 配置AuthorizationStoreRoleProvider
授权管理器(AzMan)是Windows Server 2003提供的组件。使用授权管理器可以定义角色、任务和操作。
授权管理器比ASP.NET Framework中的授权框架支持更多的功能。例如,授权管理器支持角色继承,这样一来就可以很容易地基于已有的角色创建新角色。
注解   授权管理器也可以在Windows XP专业版上使用。当然,在使用之前必须要手动进行安装。Windows Server 2003提供的管理工具包需要从微软MSDN站点下载(http://msdn.microsoft.com)。
授权管理可以用三种方式存储角色信息。即可以使用XML文件、活动目录或应用模式活动目录(ADAM)来存储所创建的授权设置。
在使用ASP.NET Framework和授权管理器之前,需要创建授权存储。角色信息将会保存在位于当前应用程序中的XML文件中。请遵照下列步骤:
(1) 通过在命令提示行上执行AzMan.msc命令运行授权管理器(见图2-16)。
(2) 通过选取菜单选项:Action(动作)→Options(选项)→Developer mode(开发模式),来将授权管理器转换为开发模式。
(3) 通过选取菜单选项:Action(动作)→New Authorization Store(新授权存储),来开启新授权存储设置对话框。
(4) 选择XML文件选项,并在存储名输入框中输入应用程序的App_Data文件夹路径。例如:
c:\Websites\MyWebsite\App_Data\WebRoles.xml
(5) 通过右键点击刚才创建的授权存储名,并选择新应用程序菜单项来创建新的授权管理器应用。为应用起名为WebRoles并输入(其他的输入项可以空着)。
图2-16 使用授权管理器
当完成以上步骤后,授权管理器会将一个新的XML文件添加到该应用程序中。该XML文件中包含了授权存储。
接下来,还需要配置ASP.NET角色管理器以使用该授权存储。代码清单2-32中的Web配置文件使用了WebRoles.xml授权存储。
代码清单2-32 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
   <add
      name="AZConnection"
      connectionString="msxml://~/App_Data/WebRoles.xml"/>
</connectionStrings>
<system.web>
    <authentication mode="Windows" />
    <roleManager enabled="true" defaultProvider="MyRoleProvider">
      <providers>
        <add
          name="MyRoleProvider"
          type="System.Web.Security.AuthorizationStoreRoleProvider"
          connectionStringName="AZConnection"
          applicationName="WebRoles"
            />
      </providers>
    </roleManager>
</system.web>
</configuration>
应该注意的是关于代码清单2-32中的配置文件所作的设置。首先,需要注意连接字符串所使用的msxml前缀:该前缀用于指出其连接字符串是表示的一个指向XML文件的连接路径。
第二,需要注意的是AuthorizationStoreRoleProvider中包含了一个applicationName属性。该属性必须包含我们在前面步骤中所创建的那个授权管理器应用的名字。
在完成了这些设置步骤以后,我们就可以像使用默认的SqlMembershipProvider那样来使用授权管理器。即可以通过Web站点管理工具或授权管理器界面来创建新的角色(见图2-17)。
图2-17 使用授权管理器创建新角色定义
2.4.4 在浏览器cookie中缓存角色
为了提高应用程序的性能,可以将用户角色信息缓存在浏览器cookie中。这样一来,角色管理器就不需要在每次用户访问页面时都对角色提供器进行查询。
将角色信息缓存在cookie中的功能默认是被禁用的。使用代码清单2-33中的Web配置文件可以开启这个功能。
代码清单2-33 Web.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
    <roleManager
      enabled="true"
      cacheRolesInCookie="true"
      createPersistentCookie="true" />
</system.web>
</configuration>
代码清单2-33中的Web配置文件开启了角色缓存功能。此外,它是将角色信息缓存在了持久型cookie而不是会话型cookie中。
注意   当角色信息缓存在cookie中后,用户的缓存角色和用户的实际角色可能会有不同步的潜在风险。如果在服务器端上更新了用户的角色信息,已经执行的应用程序并不能立即获得以更新的角色。所以需要调用Roles.Deletecookie()方法来删除缓存中的无效cookie信息。
我们可以设置和角色cookie相关的很多属性:
q cacheRolesInCookie——用于设置是否将用户的角色信息缓存在浏览器cookie中(其默认值是false);
q cookieName——用于指定缓存角色信息cookie的名字(其默认值为.ASPXROLES);
q cookiePath——用于指定和该cookie相关联的路径(其默认值为/);
q cookieProtection——用于设置如何加密和验证缓存角色信息的cookie。其可能的取值是All、Encryption、None和Validation(其默认值为All);
q cookieRequireSSL——用于指定是否需要使用安全套接字(SSL)连接来传输缓存角色信息的cookie(其默认值为false);
q cookieSlidingExpiration——用于指定是否需要通过设置页面访问超时控制来保护cookie(其默认值为true);
q cookieTimeout——用于指定以分钟为单位的cookie超时时间(其默认值为30);
q createPersistentCookie——用于指定是否要使用持久型cookie来代替会话型cookie(其默认值为false);
q domain——用于指定与cookie相关的域(其默认值是空字符串);
q maxCachedResults——用于指定cookie中最多可以缓存多少角色信息(其默认值为25)。
2.4.5 使用Roles API
Roles类公开了管理角色的主要API。如果要通过编程方式来创建角色、删除角色或将用户配备到角色上,那么就需要使用Roles类所提供的方法。
Roles类提供了下列方法:
q AddUsersToRole——用于将一组用户添加到特定角色中;
q AddUsersToRoles——用于将一组用户添加到一组角色中;
q AddUserToRole——用于将某一用户添加到特定角色中;
q AddUserToRoles——用于将某一用户添加到一组角色中;
q CreateRole——用于创建新的角色;
q DeleteCookie——用于删除保存角色信息的cookie;
q DeleteRole——用于删除特定的角色;
q FindUsersInRole——用于返回在某一角色中包含了特定用户名的一组用户;
q GetAllRoles——用于返回所有角色的列表;
q GetRolesForUser——用于返回某一用户所属的所有角色的列表;
q GetUsersInRole——用于返回某一角色中的所有用户的列表;
q IsUserInRole——用于判断某一特定的用户是否是某一特定角色中的成员;
q RemoveUserFromRole——用于从某一特定角色中移出某一特定的成员;
q RemoveUserFromRoles——用于从一组角色中移出某一特定成员;
q RemoveUsersFromRole——用于从某一特定组角色中移出一组成员;
q RemoveUsersFromRoles——用于从一组角色中移出一组成员;
q RoleExists——用于判断一个特定的角色是否存在。
代码清单2-34中的页面示例了如何使用Roles类的方法。Page_Load()方法创建了名为Sales和Managers的两个角色(如果它们还未存在)。接下来,把当前用户分配到了这两个角色中。页面正文中的GridView控件显示了当前用户所属的所有角色的列表(见图2-18)。
代码清单2-34 ShowRoles.aspx
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    void Page_Load()
    {
        // If user is not authenticated, redirect to Login page
        if (!Request.IsAuthenticated)
        {
            FormsAuthentication.RedirectToLoginPage();
            Response.End();
        }
        // Create two roles
        if (!Roles.RoleExists("Managers"))
            Roles.CreateRole("Managers");
        if (!Roles.RoleExists("Sales"))
            Roles.CreateRole("Sales");
       
        // Add current user to both roles
        if (!Roles.IsUserInRole("Managers"))
             Roles.AddUserToRole(User.Identity.Name, "Managers");
        if (!Roles.IsUserInRole("Sales"))
            Roles.AddUserToRole(User.Identity.Name, "Sales");
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
   <title>Show Roles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
   
    <h1>Your Roles</h1>
   
    <asp:GridView
        id="grdRoles"
        DataSourceID="srcRoles"
        EmptyDataText="You are not a member of any roles"
       GridLines="none"
        Runat="server" />
   
    <asp:ObjectDataSource
        id="srcRoles"
        TypeName="System.Web.Security.Roles"
        SelectMethod="GetRolesForUser"
        Runat="server" />
   
    </div>
    </form>
</body>
</html>
图2-18 显示用户所属的角色
posted @ 2009-12-20 16:09  海底的鱼  阅读(599)  评论(0)    收藏  举报