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) 环境中的某些拦截器丢弃的主要内容,如果未能解决你的问题,请参考以下文章
Asp.Net:将数据从 WCF 服务广播到 Asp.Net 客户端的最佳方式