[英]How can I reliably check client identity whilst making DCOM calls to a C# .NET 3.5 Server?
我有一個舊的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。
有什么我做錯了嗎? 以這種方式使用模擬是否有任何警告或限制? 是否有更好或不同的方式可以讓我可靠地實現我想做的事情?
非常感謝所有的幫助。
好的,所以我采取了不同的方法,並且finall提出了一種似乎有效的方法(針對8個不同的遠程用戶進行了測試)。
我放棄了Impersonation路線,轉而使用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似乎具有所需的結果,並且無論使用哪個線程來處理消息,我都能夠可靠地每次都獲得調用用戶的身份。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.