在使用WebGet调用的WCF服务中未设置Thread.CurrentPrincipal

Joe*_*Joe 12 .net asp.net ajax wcf

我有一个在IIS中托管的网站,它使用Windows身份验证并公开WCF Web服务.

我使用端点行为配置此服务:

<serviceAuthorization principalPermissionMode ="UseAspNetRoles" 
                   roleProviderName="MyRoleProvider"/>
Run Code Online (Sandbox Code Playgroud)

和绑定:

 <security mode="TransportCredentialOnly">
    <transport clientCredentialType="Ntlm" />
 </security>
Run Code Online (Sandbox Code Playgroud)

调用服务时,Thread.CurrentPrincipal将设置为a,RolePrincipal其中包含客户端的Windows标识和由配置的提供程序提供的角色.

一切都与世隔绝.

现在我添加了REST-ful Ajax调用所使用的一些其他WCF服务:Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"在svc文件中,WebGet服务契约中的AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)属性以及服务实现上的属性.

我还按照MSDN中的建议将以下咒语添加到web.config:

<system.serviceModel>
    ...
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    ...
</system.serviceModel>
Run Code Online (Sandbox Code Playgroud)

我的Ajax服务几乎按照我想要的方式工作.当它被调用时,HttpContext.Current.User被设置为RolePrincipal具有我期望的角色的a .但Thread.CurrentPrincipal仍然未经认证GenericPrincipal.

所以我需要为每个服务方法添加一行代码:

Thread.CurrentPrincipal = HttpContext.Current.User
Run Code Online (Sandbox Code Playgroud)

我可以使用配置文件中的任何咒语Thread.CurrentPrincipal来自动设置,就像普通的SOAP服务一样吗?

更新 这是来自有同样问题的人的博客,并通过实现自定义行为解决了这个问题.当然有一种方法可以开箱即用吗?

更新2 回来为此添加一个赏金,因为它在一个新项目中再次困扰我,在.NET 3.5上使用支持WCF WebGet的服务.

我已经尝试了很多选项,包括设置principalPermissionMode ="None",但没有任何效果.这是发生的事情:

  • 我导航到调用我的服务的WebGet URL: http://myserver/MyService.svc/...

  • 我在Global.asax"Application_AuthorizeRequest"中放了一个断点.当命中此断点时,"HttpContext.Current.User"和"Thread.CurrentPrincipal"都已设置为使用我配置的ASP.NET RoleProvider的"RolePrincipal".这是我想要的行为.

  • 调用我的服务的OperationContract方法时,我有第二个断点.当遇到此断点时,HttpContext.Current.User仍然引用我的RolePrincipal,但Thread.CurrentPrincipal已更改为GenericPrincipal.Aaargh.

我已经看到了实现自定义IAuthorizationPolicy的建议,如果我找不到更好的解决方案,我会调查一下,但为什么我需要实现自定义策略来利用现有的ASP.NET授权功能呢?如果我有principalPermissionMode ="UseAspNetRoles",肯定WCF应该知道我想要什么?

Ben*_*yne 6

这是个有趣的问题.我没有与您相同的设置,因此很难测试我的建议是否完全适用于您的用例,但我可以与类似项目分享对我们有用的内容.

我们如何保持Thread.CurrentPrincipalHttpContext.Current.User同步

我们编写了一个名为"AuthenticationModule"的HttpModule,它继承自IHtppModule.

然后,我们附加到HttpApplication.AuthenticateRequest请求生命周期中很早发生的事件.

在我们的AuthenticateRequest事件处理程序中,我们实现了特定于应用程序的要求,包括设置Thread.CurrentPrincipal以及必要时还有当前上下文用户.这样,您只需为整个应用程序实现一次此代码,如果它发生更改(如果您实现了自定义Principal IIDentity),则只有一个地方可以更改它.(不要在每个服务方法中复制此代码.)

public class AuthenticationModule : IHttpModule
{
    public void Dispose() { return; }

    public void Init(HttpApplication app)
    {
        app.AuthenticateRequest += new EventHandler(app_AuthenticateRequest);
    }

    void app_AuthenticateRequest(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;

        // This is what you were asking for, but hey you 
        // could change this behavior easily.
        Thread.CurrentPrincipal = app.Context.User;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们实现一个自定义IIdentity,创建一个实例,GenericPrincipal然后将它分配给两个人app.Context.User,实际上有点复杂Thread.CurrentPrincipal; 但是,以上是你要求的.

别忘了在你的新HttpModule中注册web.config!

对于集成应用程序池:

<system.webServer>
    <modules>
      <add name="AuthenticationModule" type="YourNameSpace.AuthenticationModule" preCondition="integratedMode" />
    </modules>
</system.webServer>
Run Code Online (Sandbox Code Playgroud)

对于旧的经典应用程序池,您必须将其放入 <system.web><httpModules></httpModules></system.web>

您可能需要使用AuthenticationRequest事件处理程序内部的内容和/或注册处理程序的顺序.因为我们的完全是定制的,它可能与您需要的不同.我们实际上抓住了Forms Authentication cookie,解密它等等......你可能需要ping一些内置的WindowsAuthentication方法.

我相信这是一种更通用的方式来处理您的应用程序身份验证的东西,因为它适用于所有HttpRequests是一个页面请求IHttpHandler,一些第三方组件等...这将使整个应用程序保持一致.


Jac*_*tor 1

我不知道。也许这会有所帮助

<configuration>
  <system.web>
    <identity impersonate="true" />
  </system.web>
</configuration>
Run Code Online (Sandbox Code Playgroud)

http://msdn.microsoft.com/en-us/library/134ec8tc(v=vs.80).aspx