翻译:欧盟特软件技术公司 纪俊
在第一部分我们讨论了 Provider 模型,授权与 SqlMembershipProvider 类。在这篇文章我们将把精力放到 Role Provider 与授权。
一旦确定了用户身份,您需要决定的将会是允许用户做什么和允许他们访问哪些页。通常我们管理权限的技术是将用户分如不用的组或者角色,并且根据用户的角色来分配权限。举例来说,您的应用程序可能有10000名注册用户但仅仅分为三种角色:管理员、注册用户与匿名用户。使用角色来减少网站运行的管理操作。当您想要授权或者限制网站所有的注册用户,你仅仅需要设置某个角色的权限并且不会影响到其他的用户帐号。
典型的,我们使用 web.config 文件来允许与禁止用户组来访问文件与文件夹。它们在 web.config 得段类似部分。相比于列出各个用户帐号使用角色可以更容易的覆盖更多组的用户。ASP.net 2.0 中,您可以使用 ASP.NET Web Site Administration Tool 来定义这些授权配置。
![RoleProvider class](http://odetocode.com/aimages/membership/roleprovider.jpg)
RoleProvider 类是所有 Role Provider 得基类。正如我们在第一部分提到的,RoleProvider 类定义了所有 ASP.net 2.0 Role Provider 的协议。它包括创建与删除角色、添加与删除角色中的用户以及检查给定用户的角色权限的方法。它的目的在于定义您在程序中执行授权检查会用到的所有方法。如果 ASP.net 中没有您需要的 Role Provider(您可能要在 Oracle 中存储用户角色权限),您可以自己写自己的 Provider(从 RoleProvider)并且将您的组件加入到 ASP.net 中。
如果您想与 Role Provider 交互,使用 System.Web.Security 命名空间的 Roles 类。静态 Roles 类提供了调用当前配置的 Role Provider 得方法与属性。例如,Roles.GetAllRoles 会调用当前 Role Provider 的 GetAllRoles 方法来获得全部有效的角色名称字符串数组。如果您正在进行授权检查,Roles.IsUserInRole 方法会提供很大帮助。
Role Providers
Each role provider retrieves and stores role information from a different data source.
![Derived role providers](http://odetocode.com/aimages/membership/derivedroles.jpg)
System.Web.dll 打包的每个 Role Provider 包括 SqlRoleProvider,就像第一部分提到的 SqlMembershipProvider,在 SQL Server 数据库中存储角色信息。
WindowsTokenRoleProvider 从 Windows 用户组信息中获得角色信息。WindowsTokenRoleProvider 是只读的(您不能创建新角色、或者修改角色的权限),但在程序使用 Windows 授权与禁止匿名访问时很有用。
AuthorizationStoreRoleProvider 与 Microsoft Authorization Manager (AzMan)共同协助。AzMan 可以使用储存在 XML 文件或者是 Active Directory 的角色信息。AuthorizationStoreRoleProvider 可以在局域网与广域网应用程序中的非常好但是在一个部分信任的环境中运行却非常困难。
配置
ASP.net 中的 Role Manager 默认是关闭的。您可以在网站管理工具的安全页内打开 Role Manager,浙将在程序的 web.config 文件中添加如下一段:
<system.web>
<roleManager enabled="true" />
</system.web>
在 machine.config 中有默认的 Provider 配置:
<roleManager>
<providers>
<add name="AspNetSqlRoleProvider"
connectionStringName="LocalSqlServer"
applicationName="/"
type="System.Web.Security.SqlRoleProvider, ..." />
<add name="AspNetWindowsTokenRoleProvider"
applicationName="/"
type="System.Web.Security.WindowsTokenRoleProvider, ..." />
</providers>
</roleManager>
注意 LocalSqlServer 连接字符串是 SqlRoleProvider 的默认连接字符串。正如我们在第一部分提到的那样,LocalSqlServer 是 machine.config 中定义的指向 App_data 路径下名为 aspnetdb SQL Server Express 数据库的连接字符串。如果您的 SqlRoleProvider 与 SqlMembership Providers 使用 App_Data 以外的数据库,您首先要使用 aspnet_regsql.exe 工具(在 \Windows\Microsoft.NET\Framework\v2.0.xxxx 路径下可以找到,这里的 xxxx 是当前版本的最后四个数字 )。更详细的资料请参考本文章的第一部分。
SqlRoleProvider 的 applicationName 属性在使用非 App_Data 数据库时配置起来很重要。如果您有两个网站应用程序需要共享角色权限信息,让两个程序的 applicationName 一样并让它们指向同一个数据库实例。如果您想让程序适用同一个数据库但是并不共享角色权限信息,让两个程序的 applicationName 不同。applicationName 属性将数据限定在特定的网站应用程序中。
让我们来看下 web.config 文件中配置 Membership Provider 与 Role Provider 使用本地服务器上名为 aspnetdb 的 SQL Server 数据库的例子。
<?xml version="1.0"?>
<configuration>
<connectionStrings>
<add name="MyAspNetDB"
connectionString="server=.;database=aspnetdb;integrated security=true"/>
</connectionStrings>
<system.web>
<roleManager enabled="true">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" connectionStringName="MyAspNetDB"
applicationName="/SampleRolesApp"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</roleManager>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider"
connectionStringName="MyAspNetDB"
enablePasswordRetrieval="false"
enablePasswordReset="true"
requiresQuestionAndAnswer="true"
applicationName="/SamplesRolesApp"
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="10"
passwordStrengthRegularExpression=""
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</membership>
<authentication mode="Forms" />
</system.web>
</configuration>
第一步是为 ASP.net 数据库定义连接字符串来定位。我们可以激活 roleManager 并去掉所有之前存在的从更高层配置继承过来的 Provider。如同这个文件配置的 Membership Provider 一样,这里的connectionStringName 与 applicationName 属性设置为同一个数据库与应用程序名。
如果您想使用 WindowsTokenRoleProvider,不需要做任何配置。它不需要数据库并且只能读取 Windows 的用户群组成员权限信息。使用 WindowsTokenRoleProvider 您仅仅需要在 web.config 中添加如下一句(在网站管理程序的 Providers 页也能进行配置)。
<roleManager enabled="true"
defaultProvider="AspNetWindowsTokenRoleProvider"/>
正如我们之前提到的,AuthorizationStoreRoleProvider 使用 AzMan。关于它的更详细的信息请参考“How To Use Authorization Manager from ASP.NET”与 “How To Use Active Directory Application Mode (ADAM) from ASP.NET”。
集成
一旦您配置好了 Role Provider,就该把角色信息添加到程序中,并设置对应的权限。使用 web.config 我们可以使网站应用程序的访问者限定在某些区域的特定角色。例如:将下面一段放入 web.config 会让其目录只能被 Admin 角色的用户浏览。
<system.web>
<authorization>
<allow roles="Admin"/>
<deny users="*"/>
</authorization>
</system.web>
写程序时使用 IsUserInRole 您可以对权限作细微的检查。
If Roles.IsUserInRole("Admin") Then
' perform an admin action
Else
' give user an error message
End If
您也可以使用 PrincipalPermission 属性来显式的查询用户是否属于某一角色。您可以在一个类或者一个方法中使用这个属性。如果当前的用户不属于这个角色,代码不会执行并且会抛出一个异常。
<PrincipalPermission(SecurityAction.Demand, Role:="Registered")> _
Protected Sub DoSomethingImportant()
' ...
End Sub
结论
ASP.net 2.0 中可扩展的 Provider 模型实现了我们很多年来需要自己编写的功能 - 就像 Membership 与 Role Management。这种模型可以配置、扩展,也就是说当工具栏内没有我们需要的 Provider 的时候我们可以自己编写代码来扩充它。