如何在对 C# .NET 3.5 服务器进行 DCOM 调用时可靠地检查客户端身份?

Posted

技术标签:

【中文标题】如何在对 C# .NET 3.5 服务器进行 DCOM 调用时可靠地检查客户端身份?【英文标题】:How can I reliably check client identity whilst making DCOM calls to a C# .NET 3.5 Server? 【发布时间】:2010-04-20 11:31:06 【问题描述】:

我有一个旧的 Win32 C++ DCOM 服务器,我正在重写它以使用 C# .NET 3.5。客户端应用程序位于远程 Windows XP 机器上,并且也是用 C++ 编写的。这些客户端必须保持不变,因此我必须在新的 .NET 对象上实现接口。

这已经完成,并且在接口的实现方面正在成功地工作,并且所有调用都从旧客户端正确地发出到新的 .NET 对象。

但是,我在从 DCOM 客户端获取调用用户的身份时遇到问题。为了尝试识别发起 DCOM 调用的用户,我在服务器上有以下代码...

[DllImport("ole32.dll")]
static extern int CoImpersonateClient();

[DllImport("ole32.dll")]
static extern int CoRevertToSelf();

private string CallingUser

    get
    
        string sCallingUser = null;

        if (CoImpersonateClient() == 0)
        
            WindowsPrincipal wp = System.Threading.Thread.CurrentPrincipal as WindowsPrincipal;

            if (wp != null)
            
                WindowsIdentity wi = wp.Identity as WindowsIdentity;

                if (wi != null && !string.IsNullOrEmpty(wi.Name))
                    sCallingUser = wi.Name;
            

            if (CoRevertToSelf() != 0)
                ReportWin32Error("CoRevertToSelf");
        
        else
            ReportWin32Error("CoImpersonateClient");

        return sCallingUser;
    


private static void ReportWin32Error(string sFailingCall)

    Win32Exception ex = new Win32Exception();
    Logger.Write("Call to " + sFailingCall + " FAILED: " + ex.Message);

当我获得 CallingUser 属性时,前几次返回的值是正确的,并且识别出正确的用户名,但是,在 3 或 4 个不同的用户成功拨打电话后(而且它会有所不同,所以我可以'更具体),其他用户似乎被识别为之前拨打过电话的用户。

我注意到前几个用户的 DCOM 调用在他们自己的线程上处理(也就是说,来自特定客户端的所有调用都由一个唯一的线程处理),然后后续用户由与早期用户相同的线程,并且在调用CoImpersonateClient() 之后,CurrentPrincipal 与该线程的初始用户匹配。

举例说明:

用户 Tom 进行由线程 1 处理的 DCOM 调用(CurrentPrincipal 正确识别 Tom)

用户 Dick 发出由线程 2 处理的 DCOM 调用(CurrentPrincipal 正确识别 Dick)

用户 Harry 进行由线程 3 处理的 DCOM 调用(CurrentPrincipal 正确识别 Harry)

用户 Bob 进行了由线程 3 处理的 DCOM 调用(CurrentPrincipal 错误地将他识别为 Harry)

正如您在此图中所见,来自客户端 Harry 和 Bob 的调用正在线程 3 上处理,并且服务器将调用客户端识别为 Harry。

我做错了什么吗? 以这种方式使用模拟是否有任何警告或限制? 有没有更好或不同的方法可以可靠地实现我想要做的事情?

所有帮助将不胜感激。

【问题讨论】:

【参考方案1】:

好的,所以我采用了不同的方法,最后想出了一个似乎有效的方法(针对 8 个不同的远程用户进行了测试)。

我已经放弃了模拟路线,转而使用 ClientBlankets...

[DllImport("ole32.dll")]
static extern int CoQueryClientBlanket(out IntPtr pAuthnSvc, out IntPtr pAuthzSvc,
    [MarshalAs(UnmanagedType.LPWStr)] out StringBuilder pServerPrincName, out IntPtr
    pAuthnLevel, out IntPtr pImpLevel, out IntPtr pPrivs, out IntPtr pCapabilities);

public static string CallingUser

    get
    
        IntPtr pAthnSvc = new IntPtr();
        IntPtr pAthzSvc = new IntPtr();
        StringBuilder pServerPrincName = new StringBuilder();
        IntPtr pAuthnLevel = new IntPtr();
        IntPtr pImpLevel = new IntPtr();
        IntPtr pPrivs = new IntPtr();
        IntPtr pCaps = new IntPtr(4);
        string sCallingUser = string.Empty;

        try
        
            CoQueryClientBlanket(out pAthnSvc,
                out pAthzSvc,
                out pServerPrincName,
                out pAuthnLevel,
                out pImpLevel,
                out pPrivs,
                out pCaps);
        
        catch (Exception ex)
        
            Logger.Write(ex.Message);
        
        finally
        
            sCallingUser = System.Runtime.InteropServices.Marshal.PtrToStringAuto(pPrivs);
        

        return sCallingUser;
    

使用 CoCreateClientBlanket 似乎有预期的结果,而且我每次都能可靠地获取调用用户的身份,无论使用哪个线程来处理消息。

【讨论】:

以上是关于如何在对 C# .NET 3.5 服务器进行 DCOM 调用时可靠地检查客户端身份?的主要内容,如果未能解决你的问题,请参考以下文章

将 C# .net 4 代码编译为 .net 3.5?

如何将托管 c++ 库导入 C# 应用程序(目标 .net 版本 3.5)

在 c# .Net 3.5 中,如何控制多个 WaitHandles?

如何使用 C# 在 ASP.NET 3.5 中动态设置“application/ld+json”Schema.org 元数据

如何在 c# .net CF 3.5 中使用 XmlDocument 向 xml 添加属性

我可以在面向 .Net 3.5 的项目中使用所有 C# 4.0 功能吗?