分布式应用程序的身份验证和授权方法

来源:互联网 发布:如何找淘宝代理 编辑:程序博客网 时间:2024/05/29 11:14

基于角色授权

大部分 .NET Web 应用程序都使用基于角色的授权方法。您需要考虑各种角色类型,选择最适合您的应用程序方案的方法。您有以下选项:

• .NET 角色 • Enterprise Services (COM+) 角色 • SQL Server 用户定义的数据库角色 • SQL Server 应用程序角色

.NET 角色

.NET 角色非常灵活,它围绕 IPrincipal 对象展开,这些对象包含通过身份验证的身份所属的角色列表。.NET 角色可以用于 Web 应用程序、Web 服务,或驻留在 ASP.NET (用 HttpChannel 访问)中的远程组件。

授权可以通过 .NET 角色以两种方式进行:一种以声明方式用 PrincipalPermission 命令,一种以编程方式,在代码中用强制的 PrincipalPermission 命令或 IPrincipal.IsInRole 方法。

Windows 身份验证中的 .NET 角色

如果您的应用程序使用 Windows 身份验证,则 ASP.NET 会自动构建一个 WindowsPrincipal,并将其附加到当前 Web 请求的上下文(使用 HttpContext.User)。身份验证过程完成,并且 ASP.NET 将对象附加到当前请求后,它就可用于所有后续的基于 .NET 角色的授权了。

通过身份验证的调用者的 Windows 组成员用于确定角色集。在 Windows 身份验证下,.NET 角色与 Windows 组相同。

非 Windows 身份验证中的 .NET 角色

如果您的应用程序使用非 Windows 身份验证机制(例如表单或 Passport),那么您必须编写代码来创建 GenericPrincipal 对象(或自定义 IPrincipal 对象),并用从自定义身份验证数据存储(如 SQL Server 数据库)中获得的角色集填充它。

自定义 IPrincipal 对象

基于 .NET 角色的安全机制是可扩展的。您可以开发实现 IPrincipalIIdentity 的自有类,并提供您自己的基于角色的扩展授权功能。

只要自定义 IPrincipal 对象(包含从自定义数据存储中获得的角色)(通过 HttpContext.User)附加到当前请求的上下文,就保证了基本角色的检查功能。

通过实现 IPrincipal 接口,可以确保声明和命令形式的PrincipalPermission 命令都适用于您的自定义身份。另外,您可以实现扩展的角色语义;例如,提供允许您测试和断言多个角色的成员身份的其他方法,比如 IsInMultipleRoles( string [] roles )。

Enterprise Services (COM+) 角色

使用 Enterprise Services (COM+) 角色可以将访问检查交给中间层,并允许您在连接到后端数据库时使用数据库连接池。然而,对于有意义的基于 Enterprise Services (COM+) 角色的授权,前端 Web 应用程序必须模拟原调用者的身份,并(通过 Windows 访问令牌)使将其传递到 Enterprise Services 应用程序。为此,必须在 Web 应用程序的 Web.config 文件中放入以下各项。

<authentication mode="Windows" /> <identity impersonate="true" /> 

如果使用方法级的说明性检查(以确定哪些用户可以调用哪些方法)就足够的话,则可以使用“组件服务”管理工具部署应用程序和更新角色成员。

如果需要用方法代码以编程方式进行检查,您将会失去 Enterprise Services (COM+) 角色的一些管理和部署优点,因为角色逻辑是硬编码的。

SQL Server 用户定义的数据库角色

在这种方法中,您在数据库中创建角色,根据角色指派权限,并将 Windows 组和用户帐户映射到角色。这种方法要求您将调用者身份传递到后端(如果您对 SQL Server 使用首选的 Windows 身份验证)。

SQL Server 应用程序角色

在这种方法中,将权限授予数据库中的角色,但 SQL Server 应用程序角色不包含用户和组帐户。因此,您就会失去原调用者的粒度。

在应用程序角色中,您被授权访问特定的应用程序(与一组用户相对)。此应用程序使用接受角色名和密码的内置存储过程激活角色。这种方法的一个主要缺点是它要求应用程序安全地管理凭证(角色名和相关的密码)。

.NET 角色与 Enterprise Services (COM+) 角色的对比

以下表格列出 .NET 角色和 Enterprise Services (COM+) 角色的功能对比。

表 2:Enterprise Services 角色与 .NET 角色的对比 功能 Enterprise Services 角色 .NET 角色

管理

组件服务管理工具

自定义

数据存储

COM+ 目录

自定义数据存储(如 SQL Server 或 Active Directory)

声明性

命令性

类、接口和方法级粒度

可扩展性

是(使用自定义 IPrincipal 实现)

可供所有 .NET 组件使用

只供派生自 ServicedComponent 基类的组件使用

角色成员

角色包含 Windows 组或用户帐户

当使用 WindowsPrincipal 时,角色是 Windows 组–—没有额外的抽象级别

要求显式地实现接口

是,要想获得方法级的授权,必须显式地定义和实现接口

 

使用 .NET 角色

可以使用 .NET 角色保护以下各项的安全:

• 文件 • 文件夹 • Web 页面(.aspx 文件) • Web 服务(.asmx 文件) • 对象 • 方法和属性 • 方法中的代码块

可以使用 .NET 角色保护操作(由方法和属性执行)和特定代码块的事实,意味着您可以保护对应用程序所访问的本地和远程资源的访问。

前面列表中的前四项(文件、文件夹、Web 页面和 Web 服务)是通过 UrlAuthorizationModule 保护的,它可以使用调用者的角色成员(和调用者的身份)做出授权决定。

如果您使用 Windows 身份验证,则系统会为您完成使用 .NET 角色所需的大部分工作。ASP.NET 会构建 WindowsPrincipal 对象,并由用户的 Windows 组成员确定相关的角色集。

要在非 Windows 身份验证机制中使用 .NET 角色,必须编写代码执行以下操作:

• 捕获用户凭证。 • 检验用户访问自定义数据存储(比如 SQL Server 数据库)的凭证。 • 检索角色列表,构建 GenericPrincipal 对象并将它与当前 Web 请求相关联。

GenericPrincipal 对象代表通过身份验证的用户,并用于后续的 .NET 角色检查,例如声明性的PrincipalPermission 命令和编程方式的IPrincipal.IsInRole 检查。

检查角色成员

可使用以下类型的 .NET 角色检查:

重要:.NET 角色检查依赖于 IPrincipal 对象(表示通过身份验证的用户)是否与当前请求关联。对于 ASP.NET Web 应用程序,IPrincipal 对象必须附加到 HttpContext.User。对于 Windows 窗体应用程序,IPrincipal 对象必须附加到 Thread.CurrentPrincipal

手动角色检查。对于细分授权,您可以调用 IPrincipal.IsInRole 方法,根据调用者的角色成员授权对特定代码块的访问。在检查角色成员时,AND 和 OR 逻辑均可使用。 • 声明性角色检查(方法入口)。您可以使用 PrincipalPermissionAttribute 类(可以简写为 PrincipalPermission)对方法进行注释,以声明方式请求角色成员。这些检查只支持 OR 逻辑。例如,您可以要求调用者至少属于一个特定的角色(例如,调用者必须是出纳员或一个经理)。不能用声明性检查指定调用者必须既是经理,又是出纳员。 • 命令性角色检查(在方法中检查)。可以在代码中调用 PrincipalPermission.Demand 执行细分授权逻辑。支持逻辑 AND 和 OR 操作。

角色检查示例

以下代码片段显示了一些使用编程、声明性和命令性方法的角色检查示例。

授权 Bob 执行操作:

尽管可以授权个别用户,但通常应该基于角色成员身份进行授权,这使您可以授权在应用程序中共享相同特权的用户组。

• 直接用户名检查

    GenericIdentity userIdentity = new GenericIdentity("Bob");     if (userIdentity.Name=="Bob")     {     } 
• 声明性检查
    [PrincipalPermissionAttribute(SecurityAction.Demand, User="Bob")]     public void DoPrivilegedMethod()     {     } 
• 命令性检查
    PrincipalPermission permCheckUser = new PrincipalPermission(                                                    "Bob", null);     permCheckUser.Demand(); 

授权出纳员执行操作:

• 直接角色名检查

    GenericIdentity userIdentity = new GenericIdentity("Bob");     // Role names would be retrieved from a custom data store     string[] roles = new String[]{"Manager", "Teller"};     GenericPrincipal userPrincipal = new GenericPrincipal(userIdentity,                                                            roles);     if (userPrincipal.IsInRole("Teller"))     {     } 
• 声明性检查
    [PrincipalPermissionAttribute(SecurityAction.Demand, Role="Teller")]     void SomeTellerOnlyMethod()     {     } 
• 命令性检查
    public SomeMethod()     {       PrincipalPermission permCheck = new PrincipalPermission(                                                    null,"Teller");       permCheck.Demand();       // Only Tellers can execute the following code       // •ñn members of the Teller role result in a security exception       . . .     } 

授权经理或出纳员执行操作:

• 直接角色名检查

    if (Thread.CurrentPrincipal.IsInRole("Teller") ||         Thread.CurrentPrincipal.IsInRole("Manager"))     {       // Perform privileged operations     } 
• 声明性检查
    [PrincipalPermissionAttribute(SecurityAction.Demand, Role="Teller"),      PrincipalPermissionAttribute(SecurityAction.Demand, Role="Manager")]     public void DoPrivilegedMethod()     {     } 
• 命令性检查
    PrincipalPermission permCheckTellers = new PrincipalPermission(                                                         null,"Teller");     PrincipalPermission permCheckManagers = new PrincipalPermission(                                                        null,"Manager");    (permCheckTellers.Union(permCheckManagers)).Demand(); 

授权那些既是经理又是出纳员的用户执行操作:

• 直接角色名检查

    if (Thread.CurrentPrincipal.IsInRole("Teller") &&         Thread.CurrentPrincipal.IsInRole("Manager"))     {       // Perform privileged operation     } 
• 声明性检查

不可以利用 .NET 角色以声明方式执行 AND 检查。将 PrincipalPermission 命令叠加在一起使用会产生逻辑 OR。

• 命令性检查
    PrincipalPermission permCheckTellers = new PrincipalPermission(                                                      null,"Teller");     permCheckTellers.Demand();       PrincipalPermission permCheckManagers = new PrincipalPermission(                                                      null, "Manager");     permCheckManagers.Demand(); 

 

选择身份验证机制

本部分提供指导信息,旨在帮助您选择常见应用程序方案的身份验证机制。您应该考虑从以下问题着手:

身份。仅当应用程序用户的 Windows 帐户可由受信任的机构进行身份验证,并且应用程序的 Web 服务器可以访问该机构时,才适合使用 Windows 身份验证机制。 • 凭证管理。Windows 身份验证的一个主要优点是它使您可以将凭证管理交给操作系统去做。采用非 Windows 方法(如表单身份验证),您就必须仔细考虑用户凭证的存储位置和方式。两种最常见的方法是使用: • SQL Server 数据库 • Active Directory 中的用户对象

有关将 SQL Server 用作凭证存储的安全考虑事项的更多信息,请参考“数据访问安全性”一章。

有关在自定义数据存储(包括 Active Directory)中使用表单身份验证的更多信息,请参考“ASP.NET 安全性”一章。

身份传递。您需要实现模拟/委派模式,并在操作系统级的各层间传递原调用者的安全上下文吗?例如,为了支持审核或每用户(粒度)授权。如果需要,您就需要能够模拟调用者,并将它们的安全上下文委派到下一个下游子系统,如本章前面的“传递身份”部分中的“委派”主题所描述的。 • 浏览器类型。您的用户都有 Internet Explorer 吗?或者您需要支持使用混合浏览器类型的用户群?表 3 阐述了哪些身份验证机制需要 Internet Explorer 浏览器,而哪些支持各种常见的浏览器类型。 表 3:身份验证浏览器要求 身份验证类型 是否要求 Internet Explorer 备注

表单

-

Passport

-

集成 Windows(Kerberos 或 NTLM)

Kerberos 还要求客户端和服务器使用 Windows 2000 或更高版本的操作系统,并且有为委派配置的帐户。要想了解更多信息,请参考“How To Implement Kerberos Delegation for Windows 2000”。

基本

基本身份验证是几乎所有浏览器都支持的 HTTP 1.1 协议的一部分

简要

-

证书

客户端要求 X.509 证书

 

Internet 方案

Internet 方案的基本假定条件是:

• 用户在服务器域或该服务器可达的受信任域中没有 Windows 帐户。 • 用户没有客户端证书。

图 4 显示了一个为 Internet 方案选择身份验证机制的决策树。


 

图 4. 为 Internet 应用程序选择身份验证机制

 

有关 Web 服务安全和 WS 安全规范(全球 XML 体系结构 (GXA) 倡议的一部分)的更多信息,请参考“Web Services Security”一章。

表单/ Passport 比较

这一部分总结表单和 Passport 身份验证的相对优点。

表单身份验证的优点

• 支持对照自定义数据存储(通常为 SQL Server 数据库或 Active Directory)的身份验证。 • 支持基于角色授权(包括从数据存储中查找角色)。 • 与 Web 用户界面平稳集成。 • ASP.NET 提供结构的大部分。与传统 ASP 相比,需要的自定义代码相对较少。

Passport 身份验证的优点

• Passport 是一种集中式解决方案。 • 它不需要应用程序进行凭证管理。 • 能与基于角色授权方案一起使用。 • 非常安全,因为它建立在加密技术之上。

 

Intranet / Extranet 方案

图 5 显示了一个可用于帮助为 Intranet 和 Extranet 应用方案选择一种身份验证机制的决策树。


 

图 5. 为 Intranet 和 Extranet 应用程序选择一种身份验证机制

 

身份验证机制比较

以下表格显示可用的身份验证机制的比较。

表 4:可用的身份验证方法 - Basic Digest NTLM Kerberos Certs Forms Passport

用户在服务器的域中需要 Windows 帐户

支持委派*

可以

需要 Win2K 客户端和服务器

以明文形式传递凭证(需要 SSL)

支持非 IE 浏览器

 

小结

设计分布式应用程序的身份验证和授权方法是一项具有挑战性的任务。在应用程序开发的早期阶段,正确设计身份验证和授权有助于减少许多主要的安全风险。以下总结本章中的信息:

• 使用受信任子系统资源访问模式可获得使用数据库连接池的益处。 • 如果您的应用程序没有使用 Windows 身份验证,请使用 .NET 角色检查提供授权。对照自定义数据存储检验凭证,检索角色列表并创建 GenericPrincipal 对象。将它与当前 Web 请求 (HttpContext.User) 相关联。 • 如果您的应用程序使用 Windows 身份验证,但不使用 Enterprise Services,请使用 .NET 角色。请记住,对于 Windows 身份验证,.NET 角色为 Windows 组。 • 如果您的应用程序使用 Windows 身份验证和 Enterprise Services,请考虑使用 Enterprise Services (COM+) 角色。 • 对于使用 Enterprise Services (COM+) 角色的有意义的基于角色授权,原调用者的身份必须传递到 Enterprise Services 应用程序。如果从 ASP.NET Web 应用程序中调用 Enterprise Services 应用程序,则意味着 Web 应用程序必须使用 Windows 身份验证,并配置为使用模拟。 • 以 PrincipalPermission 属性对方法进行注释,以声明方式请求角色成员。如果调用者不在指定的角色中,则不调用该方法,并且产生一个安全异常。 • 在方法代码中调用 PrincipalPermission.Demand (或使用 IPrincipal.IsInRole)以获得细分授权决策。 • 考虑实现自定义 IPrincipal 对象以获得其他角色检查语义。