ASP.Net WCF 服务的 Thread.CurrentPrincipal 被联邦 (WIF) 环境中的某些拦截器丢弃

Posted

技术标签:

【中文标题】ASP.Net WCF 服务的 Thread.CurrentPrincipal 被联邦 (WIF) 环境中的某些拦截器丢弃【英文标题】:ASP.Net WCF service's Thread.CurrentPrincipal is being thrown away by some interceptor in a Federated (WIF) environment 【发布时间】:2010-12-28 07:02:50 【问题描述】:

我有一个托管在 IIS (.svc) 中的每次调用 WCF 服务。在服务的构造函数中,我按照this article 设置了 Thread.CurrentPrincipal = HttpContext.Current.User。在这种情况下,HttpContext.Current.User 属于 Microsoft.IdentityModel.Claims.ClaimsPrincipal 类型,并且具有从我的自定义被动 STS 发回的声明。

然而,当我进入我的服务操作并检查 Thread.CurrentPrincipal 时,虽然此对象仍然是 Microsoft.IdentityModel.Claims.ClaimsIdentity 类型,但对象本身不再与 HttpContext.Current.User 相同(IsAuthenticated = false, AuthenticationType = "" and Name 在 Thread.CurrentPrincipal.Identity 上为空),而这些HttpContext.Current.User 上的值仍然正确填写。这告诉我,某些东西正在拦截对操作的调用,并将当前主体错误地更改为一些通用的、空的、未经身份验证的声明主体。

我在构造函数和操作中检查了线程 ID,两个地方都相同,并在从 HttpContext.Current 分配后的即时窗口中评估 Thread.CurrentPrincipal .User 表明在构造函数中正确设置了线程标识,因此在构造函数和方法之间肯定正在执行某些东西,并且某些东西正在改变我的 Thread.CurrentPrincipal

有没有人知道这是怎么回事,以及我可以如何防止/修复这种行为?

【问题讨论】:

【参考方案1】:

我刚刚遇到了类似的问题。我在 WCF 服务的构造函数中设置了我的自定义主体。当我离开构造函数并进入我调用的方法时,thread.currentprincipal 被一个空的覆盖。我通过添加以下行为解决了这个问题:

<serviceAuthorization principalPermissionMode="None"></serviceAuthorization>

这对我来说很好。

【讨论】:

【参考方案2】:

为 WIF 联合配置服务时,您调用

FederatedServiceCredentials.ConfigureServiceHost(this);

此调用的部分作用是在服务主机上设置 IdentityModelServiceAuthorizationManager 类型的自定义 ServiceAuthorizationManager。此授权管理器似乎在实例的激活(构造)和操作的执行之间被调用,它用 IClaimsPrincipal 的实例覆盖 Thread.CurrentPrincipal,但它似乎没有意识到它在 ASP.NET 兼容模式下运行,因此它不会从 HttpContext.Current.User 中提取主体。

我能够通过从 IdentityModelServiceAuthorizationManager 派生并覆盖 CheckAccess 方法来绕过此行为,如下所示:

public class CustomAuthorizationManager : IdentityModelServiceAuthorizationManager

    public override bool CheckAccess(System.ServiceModel.OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
    
        var result = base.CheckAccess(operationContext, ref message);

        var properties = operationContext.ServiceSecurityContext.AuthorizationContext.Properties;
        properties["Principal"] = System.Web.HttpContext.Current.User;

        return result;
    

然后将其应用于服务主机,如下所示:

protected override void InitializeRuntime()

    FederatedServiceCredentials.ConfigureServiceHost(this);
    this.Authorization.ServiceAuthorizationManager = new CustomAuthorizationManager();
    base.InitializeRuntime();

现在,当我进入我的服务操作时,我在 Thread.CurrentPrincipal 上拥有正确的 IClaimsPrincipal,因此声明性 PrincipalPermission 现在可以按预期工作.

【讨论】:

此解决方案有效,但我不确定现有 IdentityModelServiceAuthorizationManager 中是否存在错误 - 我的感觉是它应该能够判断它在 ASP.NET 兼容模式下运行,因此应该能够自动从 HttpContext.Current.User 中提取主体。我是否应该在 Microsoft.IdentityModel 1.0.0.0 发布之前将此作为错误报告给 Microsoft?【参考方案3】:

调用FederatedServiceCredentials.ConfigureServiceHost(this)的配置设置;

如下 在 system.serviceModel 添加以下内容

<extensions>
      <behaviorExtensions>
        <add name="federatedServiceHostConfiguration" type="Microsoft.IdentityModel.Configuration.ConfigureServiceHostBehaviorExtensionElement, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
      </behaviorExtensions>
    </extensions>

在里面添加下面一行

<behavior name="serviceBehavior">
          <federatedServiceHostConfiguration name="MyService" />

【讨论】:

【参考方案4】:

我的猜测是没有任何东西在拦截通话。 CurrentPrincipal 要么在您检查时被重置,要么您处于不同的线程中。

分配给 CurrentPrincipal 后立即检查它,您应该会看到正确的值。

【讨论】:

以上是关于ASP.Net WCF 服务的 Thread.CurrentPrincipal 被联邦 (WIF) 环境中的某些拦截器丢弃的主要内容,如果未能解决你的问题,请参考以下文章

RESTful 服务:WCF 与 ASP.NET MVC

从 ASP.NET 应用程序验证 WCF 服务

Asp.Net:将数据从 WCF 服务广播到 Asp.Net 客户端的最佳方式

ASP.NET 中的 WCF 模拟异常

WCF 服务将数据填充到 ASP.net 下拉列表(学习 WCF 服务)

WCF 服务 - ASP.net 托管 - 单点登录,如何传递凭据