ID #8340

服务站 - 基于WCF服务中的授权

目录

基于角色的授权

ASP.NET 角色提供程序

自定义主 体

集中化授权逻辑

基于声明的授权

声明

声明集

授权上下文t

声明转换

安全令牌服务

当分布式应 用程序开始采用面向服务这一主体时,安全性挑战将变得略有不同。您会突然意 识到所调用的每个服务都将跨越安全边界。

虽然并不绝对必要,但通常 情况下服务调用的发送方和接收方之间应该存在网络。尽管通常情况下通信框架 会自动处理身份验证,但您仍需要建立自己的授权策略和基础结构。

Windows Communication Foundation (WCF) 能够为实现服务授权提供强 大的工具。您可以选择易于使用、基于角色的系统,或者更为强大但相对更为复 杂、基于声明的 API。本文的其余部分将比较这两种系统,并介绍如何使用它们 实现可靠的服务授权。

基于角色的授权

基于角色授权的基本原理 是为用户分配一组角色。在运行时,服务代码查询相关列表以做出与安全相关的 决策。这些角色既可以来自 Windows 安全系统(也称为组),或者也可以来自 一些自定义存储,例如数据库。

Microsoft .NET Framework 中的角色 API 基于名为 IIdentity(标识信息)和 IPrincipal(角色信息)的两个接口 。IIdentity 派生类包含诸如用户名、该用户是否经过验证以及验证方式之类的 信息。

IPrincipal 派生类必须实现一个名为 IsInRole 的方法,您可以 传入角色名并获得布尔型响应。此外,主体还包含对它所封装的标识类的引用。

.NET Framework 附带几个此类接口的实现。WindowsIdentity 和 WindowsPrincipal 封装了有关 Windows 用户的详细信息。GenericIdentity 和 GenericPrincipal 可用于代表经过验证的自定义用户。

此外它还包含用 于存储主体的位置,以便将其与应用程序中当前执行的线程(例如,WCF 操作请 求)相关联。该存储位置即是 System.Threading.Thread 类中的 CurrentPrincipal 线程静态属性。典型事件过程是应用程序的一部分填充 Thread.CurrentPrincipal,以便另一部分能够访问该属性以获取其中存储的 IPrincipal 实现。随后可以对该类调用 IsInRole 方法查询当前用户的角色列 表,以便确保调用程序已经授权能够执行该操作。

这正是它在 WCF 中的 工作方式。根据已配置的验证和凭据类型,WCF 可以创建相应的 IIdentity 实 现(WindowsIdentity 用于 Windows 验证,GenericIdentity 用于大多数其他 情况)。然后,根据 WCF 服务行为 (ServiceAuthorization) 的配置创建封装 该标识并提供角色信息的 IPrincipal 实现。然后在 Thread.CurrentPrincipal 中设置该 IPrincipalset,以便服务操作可以访问到它。

除编程调用 IsInRole 执行基于角色的安全检查外,还存在名为 Principal­PermissionAttribute 的属性,可以通过它使用角色要求注释服 务操作。PrincipalPermissionAttribute 将通过在执行服务操作之前抛出 SecurityException 通知客户端授权失败。WCF 将捕获该异常,并将其转换成返 回的“拒绝访问”失败消息。WCF 客户端管道将会把该特殊失败消息 转换为 .NET 异常类型 SecurityAccessDeniedException。图 1 显示进行角色 检查和执行错误处理的各种方法。

图 1 使用错误处理进行角色检查

服务

class Service : IService {
 // only 'users' role member can call this method
 [PrincipalPermission(SecurityAction.Demand, Role = 'users')]
 public string[] GetRoles(string username) {
  // only administrators can retrieve the role information for other users
  if (ServiceSecurityContext.Current.PrimaryIdentity.Name != username) {
   if (Thread.CurrentPrincipal.IsInRole ('administrators')) {
    ...
   }
    else {
    // access denied
    throw new SecurityException();
   }
  }
 }
}

客 户端

var factory = new ChannelFactory<IService>('*');
factory.Credentials.UserName.UserName = 'bob';
factory.Credentials.UserName.Password = 'bob';
var proxy = factory.CreateChannel();
try {
Console.WriteLine('\nBob: roles for Bob --');
proxy.GetRoles('bob').ToList().ForEach(i => Console.WriteLine(i));
Console.WriteLine('\nBob: roles for Alice --');
proxy.GetRoles('alice').ToList().ForEach(i => Console.WriteLine(i));
}
catch (SecurityAccessDeniedException) {
Console.WriteLine('Access Denied\n');
}

ServiceAuthorization 服务行为控制将要与请求线程相关联的 IPrincipal 实例的创建。默认情况下,WCF 假定使用 Windows 验证并尝试使用 WindowsPrincipal 填充 Thread.CurrentPrincipal。

当客户端不是 Windows 用户时,可以选择从 ASP.NET 角色提供程序获得角色,或者实现自定 义授权策略以便从自定义数据库中获得角色。另一种替代方法是实现自定义 IPrincipal 类型,然后完全控制整个 IsInRole 实现。

ASP.NET 角色提 供程序

WCF 可以使用 ASP.NET 角色提供程序检索用户角色。您可以使用 内置提供程序之一(针对 SQL Server 或 Microsoft 授权管理器),或者通过 从 System.Web.Security.RoleProvider 派生编写自己的提供程序。

为 连接到角色提供程序,WCF 将 RoleProviderPrincipal 附加到正在执行的线程 ,该线程将所有对 IsInRole 的调用都转发给角色提供程序的 IsUserInRole 方 法。该方法接受所要查询的用户名和角色,并在该用户是指定角色的成员时返回 真,反之返回假。

图 2 显示示例自定义角色提供程序及所需配置条目。 WCF 将为服务中的每次角色检查调用角色提供程序。如果需要多次检查角色,实 现某种缓存策略以避免对角色存储的频繁轮询将大有裨益。

图 2 示例角色提供程序和配置条目

角色提供程序

class CustomRoleProvider : RoleProvider {
 public override string[] GetRolesForUser(string username) {
  if (username == 'administrator') {
   return new string[] { 'administrators', 'users' };
  }
  else {
   return new string[] { 'sales', 'marketing', 'users' };
  }
 }
  public override bool IsUserInRole(string username, string roleName)  {
  return GetRolesForUser(username).Contains(roleName);
 }
 ...
}

配置 <behaviors> <serviceBehaviors> <behavior name='security'> <serviceAuthorization principalPermissionMode='UseAspNetRoles' roleProviderName='CustomProvider' </serviceAuthorization> </behavior> </serviceBehaviors> </behaviors> <system.web> <roleManager enabled='true' defaultProvider='CustomProvider'> <providers> <add name='CustomProvider' type='Service.CustomRoleProvider, Service' /> </providers> </roleManager> </system.web>

类似缓存之类的自定义应该在角色提供程序自身中 实现,或者通过自定义 IPrincipal 实现。下面我们将进一步探究此选项。

自定义主体

另一种选项是将自定义 IPrincipal 实现提供给 WCF 。这为您提供了在每次请求的验证阶段之后隐式运行代码的机会。为此您必须创 建自己的自定义主体,并将其返回给 WCF 管道。自定义主体将随后在从 Thread.CurrentPrincipal 传给服务代码。自定义主体允许完全自定义基于角色 的安全,并公开特殊的安全逻辑供服务开发人员使用。

编写自定义主体 非常简单。只需简单地实现 IPrincipal 接口并添加自定义功能。要将主体与 WCF 集成,您必须将 ServiceAuthorization 元素中的 PrincipalPermissionMode 属性设置为 "custom" 并提供负责创建主 体并将其返回给 WCF 的授权策略。

授权策略只是实现 System.IdentityModel.Policy.IAuthorizationPolicy 接口的类。该接口的实 现必须采用名为 Evaluate 的方法,该方法将在每次请求时调用。通过该方法可 以访问 WCF 服务安全上下文并设置自定义主体。图 3 显示自定义主体、授权策 略及其相应的配置条目。

图 3 自定义主体和授权策略

主体

class CustomPrincipal : IPrincipal {
 IIdentity _identity;
 string[] _roles;
 Cache _cache = HttpRuntime.Cache;
 public CustomPrincipal (IIdentity identity) {
  _identity = identity;
 }
  // helper method for easy access (without casting)
 public static CustomPrincipal Current {
  get {
   return Thread.CurrentPrincipal as CustomPrincipal;
  }
 }
 public IIdentity Identity {
  get { return _identity; }
 }
 // return all roles (custom property)
 public string [] Roles {
  get {
   EnsureRoles();
   return _roles;
  }
 }
 // IPrincipal role check
  public bool IsInRole(string role) {
  EnsureRoles();
   return _roles.Contains(role);
 }
 // cache roles for subsequent requests
 protected virtual void EnsureRoles() {
  // caching logic omitted – see the sample download
  }
}
授权策略 class AuthorizationPolicy : IAuthorizationPolicy { // called after the authentication stage public bool Evaluate(EvaluationContext evaluationContext, ref object state) { // get the authenticated client identity from the evaluation context IIdentity client = GetClientIdentity(evaluationContext); // set the custom principal evaluationContext.Properties['Principal'] = new CustomPrincipal(client); return true; } // rest omitted } 配置 <behaviors> <serviceBehaviors> <behavior name='security'> <serviceAuthorization principalPermissionMode='Custom'> <authorizationPolicies> <add policyType='Service.AuthorizationPolicy, Service' /> </authorizationPolicies> </serviceAuthorization> </behavior> </serviceBehaviors> </behaviors>

集中化授权逻辑

到目前为止,您已了解到如何从服务操作内部访问由 WCF 安全系统提供的角色信息。但有时,如果有检查每次传入请求的集中化逻辑 ,并且不用将该逻辑传递到所有服务操作就能做出授权决策,这一点也很有用。 深入了解服务授权管理器。

服务授权管理器是从 System.ServiceModel.ServiceAuthorizationManager 派生的类。可以重写 CheckAccessCore 方法以便为每次请求运行自定义代码。在 CheckAccess 中, 可以访问到当前安全上下文及传入消息,包括消息头。当从 CheckAccess 返回 false 时,WCF 将创建“拒绝访问”错误消息并将其发送回客户端。 返回值为 true 时将授予对服务操作的访问权限。

您可以找到客户端尝 试在 WS-Addressing action 标头中调用的操作的唯一标识符。该值可以从传入 CheckAccess 的操作上下文的 IncomingMessageHeader.Action 属性中获得。 Action 值的格式如下:

ServiceNamespace/ContractName/OperationName

例如,您可能会看到如下内容:

urn:msdnmag/ServiceContract/GetRoles

WCF 将 完整的请求消息作为 ref 参数传入。这允许在消息到达服务操作(或因为授权 失败而弹回)之前检查甚至更改它。

请注意在 WCF 中消息始终只能读取 一次。这意味着在查看消息正文之前必须先创建消息的副本。可以使用以下代码 通过创建消息缓存完成此操作(大型或流式消息需要特别注意):

MessageBuffer buffer =
  operationContext.RequestContext.RequestMessage.CreateBufferedCopy(
 int.MaxValue);

创建消息副本后,可以使用标准 API 访问 其内容。在图 4 中,您可以看到一个简单服务授权管理器实现示例,它将授权 逻辑从服务操作移动到中心位置。

图 4 服务授权管理器

代码

class AuthorizationManager : ServiceAuthorizationManager {
 public override bool CheckAccess (
  OperationContext operationContext, ref Message message) {
  base.CheckAccess(operationContext, ref message);
   string action = operationContext.IncomingMessageHeaders.Action;
  if (action == 'urn:msdnmag/IService/GetRoles') {
    // messags in WCF are always read-once
   // we create one copy to work with, and one copy for WCF
   MessageBuffer buffer = operationContext.RequestContext.RequestMessage.
     CreateBufferedCopy(int.MaxValue);
   message = buffer.CreateMessage();
   // get the username value using XPath
   XPathNavigator nav = buffer.CreateNavigator();
   StandardNamespaceManager nsm = new
     StandardNamespaceManager(nav.NameTable);
   nsm.AddNamespace ('msdn', 'urn:msdnmag');
   XPathNavigator node = nav.SelectSingleNode
     ('s:Envelope/s:Body/msdn:GetRoles/msdn:username', nsm);
   string parameter = node.InnerXml;
   // check authorization
   if (operationContext.ServiceSecurityContext.PrimaryIdentity.Name ==
    parameter) {
    return true;
   }
    else {
    return (GetPrincipal(operationContext).IsInRole (
     'administrators'));
   }
  }
 return true;
 }
 // rest omitted
}
  
配置
  
<serviceAuthorization
  serviceAuthorizationManagerType='Service.AuthorizationManager, Service'>

基于声明的授权

当服务非常多且非常 复杂时,基于角色的安全性可能会变得不够强大或灵活。而且它容易使面向服务 的企业级应用程序变得极为复杂。各种使用不同客户端框架和凭据类型的客户端 需要与各种不同的后端服务传递消息。这些后端服务又会调用其他服务。有时, 这种操作以仅授权直接调用程序的受信子系统方式完成。有时也需要将最初调用 程序的标识在整个调用链转发。当外部客户端(例如合作伙伴或客户)需要访问 某些内部服务时,情况将开始变得更为复杂。

很明显在更复杂的系统中 ,IIdentity 和 IPrincipal 的功能可能不足以建模标识和授权数据。基于角色 的安全仅限用于二进制决定,并且不允许任意数据都能与主体相关联。因此需要 一种与技术无关的格式,它必须能够说明参与分布式系统的实体标识。

.NET Framework(从版本 3.0 开始)之所以包含新标识和访问控制 API (能够使用基于声明的方法处理这些需求),这就是原因。您可以在 System.IdentityModel 程序集和命名空间中找到此新 API。另外,Microsoft 最近刚刚发布其名为“Zermatt”的新标识框架预览版。新框架以 System.IdentityModel 中的类和概念为基础,它使在服务和应用程序中构建基 于声明的安全变得更加简单。需要特别注意的是 System.IdentityModel 和 Zermatt 并没有以任何形式绑定到 WCF,它可以用于声明启用任何 .NET 应用程 序。只不过这些 API 已经深入集成到 WCF 当中。

System.IdentityModel 命名空间中最重要的结构类包括 Claim、 ClaimSet、AuthorizationContext 和 AuthorizationPolicy,您需要对它们有 所理解。我们将进一步介绍其中每个类并探究它们如何集成到 WCF 安全系统当 中。

声明是能够与系统中实体相关联的一条信息。实体通常是用户,但 也可以是服务或某些资源。声明由三部分信息组成:声明类型、声明内容和声明 是否说明主体标识或主体功能。该数据结构由名为 System.IdentityModel.Claims.Claim 的类表示。此外,Claim 是 DataContract,这使其能够方便地进行序列化(当计划跨服务边界传输声明时, 这一点非常重要):

[DataContract(Namespace =
  'http://schemas.xmlsoap.org/ws/2005/05/identity')]
public class Claim {
 [DataMember(Name = 'ClaimType')]
  public string ClaimType;
 [DataMember(Name = 'Resource')]
 public object Resource;
  [DataMember(Name = 'Right')]
 public string Right;
}

ClaimType 是标识声明类型的 URI。虽然您可以建立自己的 类型 URI,但 ClaimTypes 类提供几种标准声明类型。代表名称的声明可以使用 ClaimTypes.Name 中保存的 URI 值:

http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nam e

Resource 属性包含实际声明值。请注意 Resource 是类型对象 ,这表示您能够将任意复杂的信息与声明相关联(从简单的字符串到完整的图形 )。但请记住:当涉及序列化时它可能会出现问题,如果对此比较担心,则应该 坚持使用基元类型。当我们讨论有关声明集的内容后,Right 属性的作用将变得 更加清晰。

您可以通过使用 Claim 构造函数或利用 Claim 类的静态方 法之一(对于标准声明类型)创建新的声明:

Claim purchaseLimitClaim = new Claim(
  'http://www.leastprivilege.com/claims/purchaselimit',
  5000,
 Rights.PossessProperty);
Claim nameClaim = Claim.CreateNameClaim('Alice');

声明通常不能仅凭 自身完成。它通常包含在声明集中。ClaimSet 类中包含声明列表以及对这些声 明发行方的引用:

[DataContract (Namespace='http://schemas.xmlsoap.org/ws/2005/05/identity')]
public abstract class ClaimSet : IEnumerable<Claim>, IEnumerable {
 public abstract ClaimSet Issuer { get; }
  public abstract Claim this[int index] { get; }
 public static ClaimSet System { get; }
 public static ClaimSet Windows { get; }
}

发行方是分布式系统变得更加复杂时的一个重要概念。 声明可以来自各种不同的源,例如当前服务、调用服务或安全令牌服务。发行方 与声明集相关联使服务能够辨别不同的声明来源(这也有可能影响信任决策)。

发行方还可作为声明集描述,System.IdentityModel 附带两个预定义的 发行方声明集,名为 System(对于来自系统的声明)和 Windows(对于来自 Windows 安全子系统的声明)。两者都作为 ClaimSet 类的静态属性提供。

另一个重要的概念是声明集的标识。声明集通常需要一个能够唯一标识 其描述主体的声明。这正是 Claim 类中 Right 属性的作用。声明集必须包含一 个 Right 值为 Identity 的声明(它是唯一标识符)和一些 Right 值为 PossessProperty 的声明(说明主体的其他声明)。

您可以通过创建 DefaultClaimSet 实例创建自己的声明,或者当需要更多控制时从抽象类 ClaimSet 派生创建。

DefaultClaimSet myClaimSet =
  new DefaultClaimSet(ClaimSet.System, new List<Claim> {
  new Claim(ClaimTypes.Name, 'Alice', Rights.Identity),
  new Claim(purchaseLimitClaimType, 5000, Rights.PossessProperty),
 Claim.CreateMailAddressClaim(new MailAddress ('[email protected]'))
 });

System.IdentityModel 附带两个用于将 Windows 令牌和 X.509 证书转换为声明的声明集,分别是 WindowsClaimSet 和 X509CertificateClaimSet。WCF 可以将这两个声明集用于 Windows 和 Certificate 客户端凭据类型。

ClaimSet 提供两个用于查询声明的处理 基元:FindClaims 和 ContainsClaim。FindClaims 返回指定声明类型的声明集 合,而 ContainsClaim 为您提供有关特定声明存在性的信息。

鉴于声明 集的本质,您通常最终还是需要编写自己的特定领域扩展,让它使用声明集数据 结构完成工作。在 C# 3.0 中的 Extension 方法是使用自定义功能扩展这些类 型的简便方法。(我已为 Claim、ClaimSet 和相关类型编写了扩展方法库,您 可以从 leastprivilege.com/IdentityModel 下载。)

授权上下文

在使用声明完成一些实际工作之前,您还需要了解 IdentityModel 难题 的最后一部分内容,即授权上下文,它充当声明集和转换策略(稍后将对此进行 详细介绍)的容器。WCF 通过线程静态 ServiceSecurityContext 提供授权上下 文。您可以使用图 5 中所示的代码段转储声明集以及与当前服务操作请求相关 联的声明。

图 5 查找声明和声明集

public void ShowAuthorizationContext() {
  AuthorizationContext context =
    ServiceSecurityContext.Current.AuthorizationContext;
  foreach (ClaimSet set in context.ClaimSets) {
    Console.WriteLine('\nIssuer:\n');
    Console.WriteLine(set.Issuer.GetType().Name);
    foreach (Claim claim in set.Issuer) {
      ShowClaim(claim);
    }
    Console.WriteLine('\nIssued:\n');
    Console.WriteLine(set.GetType().Name);
    foreach (Claim claim in set) {
      ShowClaim(claim);
    }
  }
}
private void ShowClaim(Claim claim) {
  Console.WriteLine('{0}\n{1}\n{2}\n',
    claim.ClaimType,
    claim.Resource,
    claim.Right);
}

当把这段代码放入 WCF 服务时,根据所 配置的客户端凭据类型将得到不同的输出。如果启用 Windows 验证,则 WCF 生 成的声明集将包含用户的 SID(标识声明)、组 SID 和用户名。对于使用客户 端证书验证的请求,声明集将包含描述主体名、公钥、指纹(标识声明)、过期 日期等的声明。对于使用简单用户名/密码对进行验证的用户,将仅包含一个用 户名标识声明。

因此,可以看出 WCF 集成的声明层将把特定技术的标识 信息(例如 Windows 令牌或证书)转换成可以使用标准 API 查询的通用数据结 构。这使得编写支持多凭据类型的服务变得更加简单,无需再硬编码到任何特定 技术的 API。如果向 WCF 添加新的凭据类型,则相应的管道将负责把专用格式 转换为声明。

声明转换

服务操作通常不关心用户的 SID 或证书 指纹,但它们需要关注特定域的标识信息,例如用户标识符、电子邮件地址或购 买限额。声明转换是将特定技术的标识详细信息转换为特定应用程序标识详细信 息的过程。

由于现在所有的标识信息都为通用格式,所以解析和分析声 明信息以创建在应用程序上下文中更有意义的新声明变得非常简单。根据 WCF 生成的声明集标识声明,可以将请求映射为应用程序用户 ID,并将相关标识和 授权信息添加到新的声明集。服务操作将随后方便地访问 WCF 授权上下文检索 感兴趣的信息,如图 6 所示:

图 6 声明转换

声明转换在授权策略中完成。我们已经使用授 权策略创建了自定义主体,但这次的目的不同。授权策略可以参与声明生成过程 ,并在 WCF 内部声明生成完成后运行。这意味着您已经可以访问与调用程序凭 据相关联的声明。

您可以查询现有声明获得标识信息,并根据这些信息 创建建模特定域声明的新声明集。然后可以将其添加到声明集列表。该列表将用 于在请求到达服务操作之前创建授权上下文。

IAuthorizationPolicy 接 口有三个必须实现的成员。Id 返回策略的唯一标识符(通常是 GUID),Issuer 返回描述该策略所建声明的发行方的声明集。而最重要的方法是 Evaluate。该 方法接收评估上下文,当仍处于创建过程中时它基本代表授权上下文。

您可以通过 EvaluationContext.ClaimSets 访问所有当前生成的声明。请勿尝 试从 Evaluate 方法中访问 ServiceSecurityContext,因为这将再次触发授权 策略并最终导致无限循环。您可以通过调用 EvaluationContext.AddClaimSet 将新的声明集添加到评估上下文,该声明集稍后将成为授权上下文的一部分。

图 7 显示实现通用模式的授权策略示例。它首先检索第一个声明集的标 识声明。该声明发送到用于检查声明并返回应用程序用户 ID 的映射组件。随后 该策略使用 ID 操作数据存储,检索声明集所包含的信息。该信息随后作为新声 明集包装并添加到评估上下文。

图 7 授权策略

class CustomerAuthorizationPolicy : IAuthorizationPolicy {
 Guid _id = Guid.NewGuid();
 // custom issuer claim set
 ApplicationIssuerClaimSet _issuer = new ApplicationIssuerClaimSet();
 public bool Evaluate (EvaluationContext evaluationContext,
  ref object state) {
  Claim id = evaluationContext.ClaimSets.FindIdentityClaim();
  string userId = Map(id);
  evaluationContext.AddClaimSet (this, new CustomerClaimSet(userId));
  return true;
 }
 public ClaimSet Issuer {
  get { return _issuer; }
 }
 public string Id {
  get { return 'CustomerAuthorizationPolicy: ' + _id.ToString(); }
 }
}

最后一步是将授权策略添加到 serviceAuthorization 行为配置。您可以添加多个策略,它们将按照添加的顺序调用。这意味着您可以 编写多步骤授权策略,其中的单个策略依赖于前一个策略添加的值。这非常适合 更为复杂的方案:

<serviceAuthorization>
  <authorizationPolicies>
  <add policyType='LeastPrivilege.CustomerAuthorizationPolicy, Service' />
  <add policyType='some_other_policy' />
  </authorizationPolicies>
</serviceAuthorization>

如果再次运行以前的代码检 查授权上下文,您将得到新的声明集和声明。服务操作将使用相似的代码检查声 明以进行授权(请参阅图 8)。

图 8 检查声明授权

public void PlaceOrder(Order order) {
  int purchaseLimit = GetPurchaseLimit();
 if (Order.Total > purchaseLimit) {
  // do appropriate action
 }
}
private int GetPurchaseLimit() {
 AuthorizationContext context =
  ServiceSecurityContext.Current.AuthorizationContext;
 foreach (ClaimSet set in context.ClaimSets) {
  foreach (Claim claim in set.FindClaims(
    Constants.PurchaseLimitClaimType,
   Rights.PossessProperty)) {
   return int.Parse(claim.Resource.ToString());
  }
 }
 throw new Exception('Claim not found');
}

服务授权管理器也能与基于声明的授权进行协作。WCF 将操 作上下文传递到 CheckAccessCore 方法中。从那里可以到达提供对授权上下文 进行访问的服务安全上下文。这使得您可以在一个位置集中某些授权决策。

安全令牌服务

安全令牌服务 (STS) 是允许进一步合并安全逻辑 的工具。STS 的典型任务是验证用户,随后创建可以包含声明的安全令牌。客户 端必须首先使用 STS 进行验证,然后将返回的令牌转发到客户端希望进行通信 的服务。

因为 STS 了解服务(该信息是令牌请求的一部分),所以它可 以进行集中授权并预先生成服务所需的声明。这样声明转换完全不需要在服务端 点进行,它可以通过 STS 集中完成。当系统复杂到一定程度时,它可以大幅简 化安全基础结构。

当多个信任域联合时,安全令牌服务也是重要的基础 结构组件。通过在多个令牌服务间建立信任,您可以跨越服务所能使用的信任边 界交换安全令牌。

WCF 具备支持前述方案的自动客户端/服务端,以及编 写 STS 所需的所有基类。但正确实现所有 WS-* 相关规范是一项非常复杂的任 务。您应该购买商业 STS 或使用更高级别的工具包(例如,Zermatt)编写自定 义规范。即将面世的 Microsoft Active Directory 联合身份验证服务版本旨在 为 WCF 提供功能完备的 STS。

请将您想询问的问题和提出的意见发送至 [email protected]

Dominick Baier 是德国 thinktecture (www.thinktecture.com) 的安全咨询师。此外,他还是 DevelopMentor (develop.com) 的安全和 WCF 课程负责人和开发人员安全 MVP,同时也是 《Developing More-Secure Microsoft ASP.NET 2.0 Applications》一书的作 者。您可以访问他在 leastprivilege.com 开设的博客。

Christian Weyer 是 thinktecture 的共同创始人之一,也是一位首席架构师,曾用 Java 、COM、DCOM、COM+、Web Services、WCF 和其他技术进行分布式应用程序的建 模和实现。如果要与他联系,请访问 www.thinktecture.com/staff/christian 。

本文配套源码


2011-07-02 10:00
阅读:
I'm VC , Just U know Y
本站部分文章来源于互联网,版权归原作者所有。

延伸阅读:

《WCF技术内幕》20:第2部分_第5章_消息:Message类

《WCF技术内幕》21:第2部分_第5章_消息:WCF XML

《WCF技术内幕》22:第2部分_第5章_消息:XmlDict

《WCF技术内幕》23

《WCF技术内幕》24:第2部分_第5章_消息:创建一