以编程方式模拟web服务的固定窗口标识
本文关键字:窗口 标识 服务 编程 方式 模拟 web | 更新日期: 2023-09-27 17:53:16
我有一个web服务(旧的web服务,而不是WCF),我使用IIS 7.0与该web服务通信。IIS 7.0只启用了Windows身份验证(甚至禁用了匿名)。在进行服务调用时,我需要能够在代码中指定特定的windows标识。我发现很多地方表明这可以在配置文件中以以下方式完成…
<authentication mode="Windows" />
<identity impersonate="true" userName="UserName" password="P@ssw0rd" />
但是我需要在代码中做同样的事情。我相信很多人都在想"你为什么要那样做"。不用做冗长的解释,最简单的回答就是因为这些是我的需求。
下面是我的代码…
HttpTransportBindingElement transport = useHttps ? new HttpsTransportBindingElement() : new HttpTransportBindingElement();
transport.ManualAddressing = false;
transport.MaxBufferPoolSize = 134217728; // 128MB
transport.MaxReceivedMessageSize = 134217728; // 128MB
transport.AllowCookies = false;
transport.AuthenticationScheme = AuthenticationSchemes.Negotiate;
transport.BypassProxyOnLocal = false;
transport.DecompressionEnabled = true;
transport.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
transport.KeepAliveEnabled = true;
transport.MaxBufferSize = 134217728; // 128MB,
transport.ProxyAuthenticationScheme = AuthenticationSchemes.Negotiate;
transport.Realm = "";
transport.TransferMode = TransferMode.Buffered;
transport.UnsafeConnectionNtlmAuthentication = false;
transport.UseDefaultWebProxy = false;
TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement
{
MaxReadPoolSize = 64,
MaxWritePoolSize = 16,
MessageVersion = MessageVersion.Soap12,
WriteEncoding = Encoding.UTF8,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxDepth = 32,
MaxStringContentLength = 134217728, // 128MB
MaxArrayLength = 134217728, // 128MB
MaxBytesPerRead = 4096,
MaxNameTableCharCount = 16384
}
};
CustomBinding binding = new CustomBinding();
binding.Elements.Add(encoding);
binding.Elements.Add(transport);
ServicePointManager.Expect100Continue = false;
generalSoapClient general = new generalSoapClient(binding, new EndpointAddress("http://localhost/site/ws/general.asmx"));
NetworkCredential iisCredentials = new NetworkCredential("UserName", "P@ssw0rd");
general.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
general.ClientCredentials.Windows.ClientCredential = iisCredentials;
string session = general.CreateDomainUserSessionFromInstance();
客户端的.config文件中没有定义任何内容。
我的web服务方法看起来像这样(一些代码丢失,不相关的身份验证)…
[WebMethod(EnableSession = true)]
[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
public string CreateDomainUserSessionFromInstance()
{
if(HttpContext.Current.User != null && HttpContext.Current.User.Identity.IsAuthenticated)
{
WindowsIdentityRequest authenticationRequest = new WindowsIdentityRequest(instanceName, HttpContext.Current.User.Identity as WindowsIdentity);
response = authManager.Login(authenticationRequest);
}
return response.SessionContext.SessionToken;
}
我的网页。服务器端的配置如下所示:
<system.web>
<authentication mode="Windows" />
<identity impersonate="true" />
<authorization>
<!--<allow users="*" />-->
<deny users="?" />
</authorization>
</system.web>
<customBinding>
<binding name="textHttpBinding" receiveTimeout="00:05:00" sendTimeout="00:05:00">
<textMessageEncoding>
<readerQuotas maxArrayLength="1024000000" maxStringContentLength="1024000000" />
</textMessageEncoding>
<httpTransport maxReceivedMessageSize="1024000000" maxBufferSize="1024000000" authenticationScheme="Negotiate" />
</customBinding>
当我有<deny users="?" />
时,我得到以下错误…" HTTP请求未经授权,客户端身份验证方案为'协商'。从服务器接收到的身份验证头是" "有人告诉我它应该是<allow users="*" />
,但当我这样做时,我可以进入web服务,但HttpContext.Current.User.Identity.IsAuthenticated
是假的,.Name
是空的,我在互联网上读到的是它需要是deny users="?" />
来拒绝匿名访问。
我是web服务的新手,所以不幸的是,大部分代码对我来说都是希腊文。我们的web服务最初允许匿名身份验证,但要求已更改为需要windows身份验证。
我花了几天时间阅读了许多网站,试图正确配置所有内容,但似乎找不到正确的组合。
我做错了什么?是很简单还是我搞错了?
下面是我用来模拟的一个类:
public class Impersonator :
IDisposable
{
private const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
public Impersonator(
string userName,
string domainName,
string password )
{
ImpersonateValidUser( userName, domainName, password );
}
public void Dispose()
{
UndoImpersonation();
}
#region P/Invoke.
// ------------------------------------------------------------------
[DllImport("advapi32.dll", SetLastError=true)]
private static extern int LogonUser(
string lpszUserName,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern int DuplicateToken(
IntPtr hToken,
int impersonationLevel,
ref IntPtr hNewToken);
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
private static extern bool RevertToSelf();
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private static extern bool CloseHandle(
IntPtr handle);
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;
#region Private member.
// ------------------------------------------------------------------
/// <summary>
/// Does the actual impersonation.
/// </summary>
/// <param name="userName">The name of the user to act as.</param>
/// <param name="domainName">The domain name of the user to act as.</param>
/// <param name="password">The password of the user to act as.</param>
private void ImpersonateValidUser(
string userName,
string domain,
string password )
{
WindowsIdentity tempWindowsIdentity = null;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;
try
{
if ( RevertToSelf() )
{
if ( LogonUser(
userName,
domain,
password,
LOGON32_LOGON_NEW_CREDENTIALS,
LOGON32_PROVIDER_DEFAULT,
ref token ) != 0 )
{
if ( DuplicateToken( token, 2, ref tokenDuplicate ) != 0 )
{
tempWindowsIdentity = new WindowsIdentity( tokenDuplicate );
impersonationContext = tempWindowsIdentity.Impersonate();
}
else
{
throw new Win32Exception( Marshal.GetLastWin32Error() );
}
}
else
{
throw new Win32Exception( Marshal.GetLastWin32Error() );
}
}
else
{
throw new Win32Exception( Marshal.GetLastWin32Error() );
}
}
finally
{
if ( token!= IntPtr.Zero )
{
CloseHandle( token );
}
if ( tokenDuplicate!=IntPtr.Zero )
{
CloseHandle( tokenDuplicate );
}
}
}
/// <summary>
/// Reverts the impersonation.
/// </summary>
private void UndoImpersonation()
{
if ( impersonationContext.IsNotNull() )
{
impersonationContext.Undo();
}
}
private WindowsImpersonationContext impersonationContext = null;
// ------------------------------------------------------------------
#endregion
}