通过两个Web服务(从WCF到WebApi)从WPF应用程序验证用户

时间:2016-04-25 11:13:39

标签: c# asp.net-web-api owin windows-authentication wcf-security

我有以下情况:

WPF client application -> WCF Service -> WebApi Service

我希望能够在WebApi服务中验证客户端应用程序的用户。我不需要完全模拟/委派 - 我要求的只是客户端的登录ID,因为我使用的是第三方授权系统的用户ID。 WCF服务和Web Api服务都在同一台服务器上。

我正在尝试的当前方法是模仿WindowsIdentity,如下所示。

1。使用Owin自行托管的WebApi服务

    WebApp.Start(options,
    builder =>
    {
        // Authenticate POST requests, but not GET requests
        // Adapted from: http://stackoverflow.com/questions/17457382/windows-authentication-with-signalr-and-owin-self-hosting
        var listener = (HttpListener)builder.Properties[typeof(HttpListener).FullName];
        listener.AuthenticationSchemes = 
            AuthenticationSchemes.Negotiate | AuthenticationSchemes.Anonymous;
        listener.AuthenticationSchemeSelectorDelegate =
            request => (request.HttpMethod == HttpMethod.Get.Method)
                ? AuthenticationSchemes.Anonymous
                : AuthenticationSchemes.Negotiate;

        // etc
    });

2。 WCF服务

<system.web><authentication mode="Windows" />

<bindings>

<binding name="BasicHttpEndpointBinding">
  <security mode="TransportCredentialOnly">
    <transport clientCredentialType="Windows" />
  </security>
</binding>

在我想要冒充的特定功能的代码中:

WindowsIdentity callerIdentity = ServiceSecurityContext.Current.WindowsIdentity; 

using (callerIdentity.Impersonate())
{
    var request = ...;
    request.ImpersonationLevel = TokenImpersonationLevel.Impersonation;
    request.UseDefaultCredentials = true;

    // Use request to call Web Api
}

第3。在客户端:

<endpointBehaviors>
  <behavior name="ImpersonationBehavior">
    <clientCredentials>
      <windows allowedImpersonationLevel="Impersonation" />
    </clientCredentials>
  </behavior>
</endpointBehaviors>

通过这个设置,在我的本地PC上,我看到WCF服务尝试连接到WebApi服务时出错:

{"An attempt was made to access a socket in a way forbidden by its access permissions 127.0.0.1:9102"}

(请注意,使用WindowsIdentity callerIdentity = WindowsIdentity.GetCurrent();代替WindowsIdentity callerIdentity = ServiceSecurityContext.Current.WindowsIdentity;可以正常工作 - 尽管显然这是使用WCF用户而不是客户端应用用户)

我的问题 - 这是在Web Api服务中确定用户名的最明智的方法吗?甚至可能这样吗?如果是这样,任何想法如何调试“禁止”错误并使这个设置工作?

1 个答案:

答案 0 :(得分:0)

对于任何有兴趣的人,我设法通过更改以下内容来实现这一目标。

  1. 以管理员身份运行这两项服务。 (我相信使用正确的配置,这不是必需的 - 但这对我的目的来说已经足够了)

  2. 确保端口保留URL与WebApi启动参数中指定的URL完全匹配(请参阅:Self hosted OWIN and urlacl)。就我而言,我使用以下WebApp.Start(...)参数:

    string baseAddress = "http://+:9100";
    StartOptions options = new StartOptions();
    options.Urls.Add(baseAddress);
    
  3. 以下为netsh:

    netsh http add urlacl url=http://+:9111/ user=EVERYONE
    
    1. 在WCF服务中,我想要使用模拟的服务实现中的方法添加了以下行为:

      [OperationBehavior(Impersonation = ImpersonationOption.Required)]
      
    2. ...对于本合同中的其他方法,我需要添加以下内容

          [OperationBehavior(Impersonation = ImpersonationOption.NotAllowed)]
      
      1. 我使用“localhost”而不是显式主机名从WCF服务引用了WebApi服务。不确定是否需要这样做。

      2. 运行WCF服务的用户需要具有使用模拟的权限(如果以管理员身份运行,则应该已设置)。使用gpedit.msc;导航到本地计算机策略 - &gt;计算机配置 - &gt; Windows设置 - &gt;安全设置 - &gt;本地政策 - &gt;用户权利分配;确保“身份验证后模拟客户端”包含您运行WCF服务的用户。 (摘自:https://blogs.technet.microsoft.com/askperf/2007/10/16/wmi-troubleshooting-impersonation-rights/

      3. 最后一步是从问题/这个答案中找出所需的最小配置......我想我会留下另一天: - )