NegotiateStream 类
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
提供一个流,该流使用 Negotiate 安全协议在客户端-服务器通信中对客户端和服务器(可选)进行身份验证。
public ref class NegotiateStream : System::Net::Security::AuthenticatedStream
public class NegotiateStream : System.Net.Security.AuthenticatedStream
[System.Runtime.Versioning.UnsupportedOSPlatform("tvos")]
public class NegotiateStream : System.Net.Security.AuthenticatedStream
type NegotiateStream = class
inherit AuthenticatedStream
[<System.Runtime.Versioning.UnsupportedOSPlatform("tvos")>]
type NegotiateStream = class
inherit AuthenticatedStream
Public Class NegotiateStream
Inherits AuthenticatedStream
- 继承
- 继承
- 属性
示例
以下示例演示使用 NegotiateStream的客户端-服务器连接的客户端。 客户端以异步方式对服务器进行身份验证并发送消息。
#using <System.dll>
using namespace System;
using namespace System::Net;
using namespace System::Net::Security;
using namespace System::Net::Sockets;
using namespace System::Text;
// The following class displays the properties of an authenticatedStream.
public ref class AuthenticatedStreamReporter
{
public:
static void DisplayProperties( AuthenticatedStream^ stream )
{
Console::WriteLine( L"IsAuthenticated: {0}", stream->IsAuthenticated );
Console::WriteLine( L"IsMutuallyAuthenticated: {0}", stream->IsMutuallyAuthenticated );
Console::WriteLine( L"IsEncrypted: {0}", stream->IsEncrypted );
Console::WriteLine( L"IsSigned: {0}", stream->IsSigned );
Console::WriteLine( L"IsServer: {0}", stream->IsServer );
}
};
public ref class ASynchronousAuthenticatingTcpClient
{
private:
static TcpClient^ client = nullptr;
public:
void Main()
{
// Establish the remote endpoint for the socket.
// For this example, use the local machine.
IPHostEntry^ ipHostInfo = Dns::GetHostEntry( Dns::GetHostName() );
IPAddress^ ipAddress = ipHostInfo->AddressList[ 0 ];
// Client and server use port 11000.
IPEndPoint^ remoteEP = gcnew IPEndPoint( ipAddress,11000 );
// Create a TCP/IP socket.
client = gcnew TcpClient;
// Connect the socket to the remote endpoint.
client->Connect( remoteEP );
Console::WriteLine( L"Client connected to {0}.", remoteEP );
// Ensure the client does not close when there is
// still data to be sent to the server.
client->LingerState = (gcnew LingerOption( true,0 ));
// Request authentication.
NetworkStream^ clientStream = client->GetStream();
NegotiateStream^ authStream = gcnew NegotiateStream( clientStream,false );
// Pass the NegotiateStream as the AsyncState object
// so that it is available to the callback delegate.
IAsyncResult^ ar = authStream->BeginAuthenticateAsClient( gcnew AsyncCallback( EndAuthenticateCallback ), authStream );
Console::WriteLine( L"Client waiting for authentication..." );
// Wait until the result is available.
ar->AsyncWaitHandle->WaitOne();
// Display the properties of the authenticated stream.
AuthenticatedStreamReporter::DisplayProperties( authStream );
// Send a message to the server.
// Encode the test data into a byte array.
array<Byte>^message = Encoding::UTF8->GetBytes( L"Hello from the client." );
ar = authStream->BeginWrite( message, 0, message->Length, gcnew AsyncCallback( EndWriteCallback ), authStream );
ar->AsyncWaitHandle->WaitOne();
Console::WriteLine( L"Sent {0} bytes.", message->Length );
// Close the client connection.
authStream->Close();
Console::WriteLine( L"Client closed." );
}
// The following method is called when the authentication completes.
static void EndAuthenticateCallback( IAsyncResult^ ar )
{
Console::WriteLine( L"Client ending authentication..." );
NegotiateStream^ authStream = dynamic_cast<NegotiateStream^>(ar->AsyncState);
// End the asynchronous operation.
authStream->EndAuthenticateAsClient( ar );
// Console.WriteLine("AllowedImpersonation: {0}", authStream.AllowedImpersonation);
}
// The following method is called when the write operation completes.
static void EndWriteCallback( IAsyncResult^ ar )
{
Console::WriteLine( L"Client ending write operation..." );
NegotiateStream^ authStream = dynamic_cast<NegotiateStream^>(ar->AsyncState);
// End the asynchronous operation.
authStream->EndWrite( ar );
}
};
void main()
{
ASynchronousAuthenticatingTcpClient^ aatc = gcnew ASynchronousAuthenticatingTcpClient;
aatc->Main();
}
using System;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Text;
namespace Examples.NegotiateStreamExample
{
public class ASynchronousAuthenticatingTcpClient
{
static TcpClient client = null;
public static void Main(String[] args)
{
// Establish the remote endpoint for the socket.
// For this example, use the local machine.
IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost");
IPAddress ipAddress = ipHostInfo.AddressList[0];
// Client and server use port 11000.
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
client = new TcpClient();
// Connect the socket to the remote endpoint.
client.Connect(remoteEP);
Console.WriteLine("Client connected to {0}.", remoteEP.ToString());
// Ensure the client does not close when there is
// still data to be sent to the server.
client.LingerState = new LingerOption(true, 0);
// Request authentication.
NetworkStream clientStream = client.GetStream();
NegotiateStream authStream = new NegotiateStream(clientStream, false);
// Pass the NegotiateStream as the AsyncState object
// so that it is available to the callback delegate.
Task authenticateTask = authStream
.AuthenticateAsClientAsync()
.ContinueWith(task =>
{
Console.WriteLine("Client ending authentication...");
Console.WriteLine("ImpersonationLevel: {0}", authStream.ImpersonationLevel);
});
Console.WriteLine("Client waiting for authentication...");
// Wait until the result is available.
authenticateTask.Wait();
// Display the properties of the authenticated stream.
AuthenticatedStreamReporter.DisplayProperties(authStream);
// Send a message to the server.
// Encode the test data into a byte array.
byte[] message = Encoding.UTF8.GetBytes("Hello from the client.");
Task writeTask = authStream
.WriteAsync(message, 0, message.Length)
.ContinueWith(task =>
{
Console.WriteLine("Client ending write operation...");
});
writeTask.Wait();
Console.WriteLine("Sent {0} bytes.", message.Length);
// Close the client connection.
authStream.Close();
Console.WriteLine("Client closed.");
}
}
// The following class displays the properties of an authenticatedStream.
public class AuthenticatedStreamReporter
{
public static void DisplayProperties(AuthenticatedStream stream)
{
Console.WriteLine("IsAuthenticated: {0}", stream.IsAuthenticated);
Console.WriteLine("IsMutuallyAuthenticated: {0}", stream.IsMutuallyAuthenticated);
Console.WriteLine("IsEncrypted: {0}", stream.IsEncrypted);
Console.WriteLine("IsSigned: {0}", stream.IsSigned);
Console.WriteLine("IsServer: {0}", stream.IsServer);
}
}
}
Imports System.Text
Imports System.Net.Sockets
Imports System.Net.Security
Imports System.Net
Namespace Examples.NegotiateStreamExample
Public Class ASynchronousAuthenticatingTcpClient
Shared client As TcpClient = Nothing
Public Shared Sub Main(args As String())
' Establish the remote endpoint for the socket.
' For this example, use the local machine.
Dim ipHostInfo = Dns.GetHostEntry("localhost")
Dim ipAddress = ipHostInfo.AddressList(0)
' Client and server use port 11000.
Dim remoteEP As New IPEndPoint(ipAddress, 11000)
' Create a TCP/IP socket.
client = New TcpClient()
' Connect the socket to the remote endpoint.
client.Connect(remoteEP)
Console.WriteLine("Client connected to {0}.", remoteEP.ToString())
' Ensure the client does not close when there is
' still data to be sent to the server.
client.LingerState = (New LingerOption(True, 0))
' Request authentication.
Dim clientStream = client.GetStream()
Dim authStream As New NegotiateStream(clientStream, False)
' Pass the NegotiateStream as the AsyncState object
' so that it is available to the callback delegate.
Dim ar = authStream.BeginAuthenticateAsClient(
New AsyncCallback(AddressOf EndAuthenticateCallback), authStream)
Console.WriteLine("Client waiting for authentication...")
' Wait until the result is available.
ar.AsyncWaitHandle.WaitOne()
' Display the properties of the authenticated stream.
AuthenticatedStreamReporter.DisplayProperties(authStream)
' Send a message to the server.
' Encode the test data into a byte array.
Dim message = Encoding.UTF8.GetBytes("Hello from the client.")
ar = authStream.BeginWrite(message, 0, message.Length,
New AsyncCallback(AddressOf EndWriteCallback), authStream)
ar.AsyncWaitHandle.WaitOne()
Console.WriteLine("Sent {0} bytes.", message.Length)
' Close the client connection.
authStream.Close()
Console.WriteLine("Client closed.")
End Sub
' The following method is called when the authentication completes.
Public Shared Sub EndAuthenticateCallback(ar As IAsyncResult)
Console.WriteLine("Client ending authentication...")
Dim authStream = CType(ar.AsyncState, NegotiateStream)
Console.WriteLine("ImpersonationLevel: {0}", authStream.ImpersonationLevel)
' End the asynchronous operation.
authStream.EndAuthenticateAsClient(ar)
End Sub
' The following method is called when the write operation completes.
Public Shared Sub EndWriteCallback(ar As IAsyncResult)
Console.WriteLine("Client ending write operation...")
Dim authStream = CType(ar.AsyncState, NegotiateStream)
' End the asynchronous operation.
authStream.EndWrite(ar)
End Sub
End Class
' The following class displays the properties of an AuthenticatedStream.
Public Class AuthenticatedStreamReporter
Public Shared Sub DisplayProperties(stream As AuthenticatedStream)
Console.WriteLine("IsAuthenticated: {0}", stream.IsAuthenticated)
Console.WriteLine("IsMutuallyAuthenticated: {0}", stream.IsMutuallyAuthenticated)
Console.WriteLine("IsEncrypted: {0}", stream.IsEncrypted)
Console.WriteLine("IsSigned: {0}", stream.IsSigned)
Console.WriteLine("IsServer: {0}", stream.IsServer)
End Sub
End Class
End Namespace
下面的代码示例演示客户端-服务器连接的服务器端,该连接使用 NegotiateStream 对客户端进行身份验证并读取客户端发送的消息。
#using <System.dll>
using namespace System;
using namespace System::Net;
using namespace System::Net::Security;
using namespace System::Net::Sockets;
using namespace System::Security::Authentication;
using namespace System::Security::Principal;
using namespace System::Text;
using namespace System::IO;
using namespace System::Threading;
// ClientState is the AsyncState object.
private ref class ClientState
{
private:
AuthenticatedStream^ authStream;
TcpClient^ client;
array<Byte>^buffer;
StringBuilder^ message;
ManualResetEvent^ waiter;
internal:
ClientState( AuthenticatedStream^ a, TcpClient^ theClient )
{
authStream = a;
client = theClient;
message = nullptr;
buffer = gcnew array<Byte>(2048);
waiter = gcnew ManualResetEvent( false );
}
internal:
property TcpClient^ Client
{
TcpClient^ get()
{
return client;
}
}
property AuthenticatedStream^ AuthStream
{
AuthenticatedStream^ get()
{
return authStream;
}
}
property array<Byte>^ Buffer
{
array<Byte>^ get()
{
return buffer;
}
}
property StringBuilder^ Message
{
StringBuilder^ get()
{
if ( message == nullptr )
message = gcnew StringBuilder;
return message;
}
}
property ManualResetEvent^ Waiter
{
ManualResetEvent^ get()
{
return waiter;
}
}
};
public ref class AsynchronousAuthenticatingTcpListener
{
public:
int Main()
{
// Create an IPv4 TCP/IP socket.
TcpListener^ listener = gcnew TcpListener( IPAddress::Any,11000 );
// Listen for incoming connections.
listener->Start();
while ( true )
{
TcpClient^ clientRequest = nullptr;
// Application blocks while waiting for an incoming connection.
// Type CNTL-C to terminate the server.
clientRequest = listener->AcceptTcpClient();
Console::WriteLine( L"Client connected." );
// A client has connected.
try
{
AuthenticateClient( clientRequest );
}
catch ( Exception^ e )
{
Console::WriteLine( e );
continue;
}
}
}
static void AuthenticateClient( TcpClient^ clientRequest )
{
NetworkStream^ stream = clientRequest->GetStream();
// Create the NegotiateStream.
NegotiateStream^ authStream = gcnew NegotiateStream( stream,false );
// Save the current client and NegotiateStream instance
// in a ClientState object.
ClientState^ cState = gcnew ClientState( authStream,clientRequest );
// Listen for the client authentication request.
authStream->BeginAuthenticateAsServer( gcnew AsyncCallback( EndAuthenticateCallback ), cState );
// Wait until the authentication completes.
cState->Waiter->WaitOne();
cState->Waiter->Reset();
authStream->BeginRead( cState->Buffer, 0, cState->Buffer->Length, gcnew AsyncCallback( EndReadCallback ), cState );
cState->Waiter->WaitOne();
// Finished with the current client.
authStream->Close();
clientRequest->Close();
}
// The following method is invoked by the
// BeginServerAuthenticate callback delegate.
static void EndAuthenticateCallback( IAsyncResult^ ar )
{
// Get the saved data.
ClientState^ cState = dynamic_cast<ClientState^>(ar->AsyncState);
TcpClient^ clientRequest = cState->Client;
NegotiateStream^ authStream = dynamic_cast<NegotiateStream^>(cState->AuthStream);
Console::WriteLine( L"Ending authentication." );
// Any exceptions that occurred during authentication are
// thrown by the EndServerAuthenticate method.
try
{
// This call blocks until the authentication is complete.
authStream->EndAuthenticateAsServer( ar );
}
catch ( AuthenticationException^ e )
{
Console::WriteLine( e );
Console::WriteLine( L"Authentication failed - closing connection." );
cState->Waiter->Set();
return;
}
catch ( Exception^ e )
{
Console::WriteLine( e );
Console::WriteLine( L"Closing connection." );
cState->Waiter->Set();
return;
}
// Display properties of the authenticated client.
IIdentity^ id = authStream->RemoteIdentity;
Console::WriteLine( L"{0} was authenticated using {1}.", id->Name, id->AuthenticationType );
cState->Waiter->Set();
}
static void EndReadCallback( IAsyncResult^ ar )
{
// Get the saved data.
ClientState^ cState = dynamic_cast<ClientState^>(ar->AsyncState);
TcpClient^ clientRequest = cState->Client;
NegotiateStream^ authStream = dynamic_cast<NegotiateStream^>(cState->AuthStream);
// Get the buffer that stores the message sent by the client.
int bytes = -1;
// Read the client message.
try
{
bytes = authStream->EndRead( ar );
cState->Message->Append( Encoding::UTF8->GetChars( cState->Buffer, 0, bytes ) );
if ( bytes != 0 )
{
authStream->BeginRead( cState->Buffer, 0, cState->Buffer->Length, gcnew AsyncCallback( EndReadCallback ), cState );
return;
}
}
catch ( Exception^ e )
{
// A real application should do something
// useful here, such as logging the failure.
Console::WriteLine( L"Client message exception:" );
Console::WriteLine( e );
cState->Waiter->Set();
return;
}
IIdentity^ id = authStream->RemoteIdentity;
Console::WriteLine( L"{0} says {1}", id->Name, cState->Message );
cState->Waiter->Set();
}
};
void main()
{
AsynchronousAuthenticatingTcpListener^ aatl = gcnew AsynchronousAuthenticatingTcpListener;
aatl->Main();
}
using System;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Principal;
using System.Text;
using System.IO;
using System.Threading;
namespace Examples.NegotiateStreamExample
{
public class AsynchronousAuthenticatingTcpListener
{
public static void Main()
{
// Create an IPv4 TCP/IP socket.
TcpListener listener = new TcpListener(IPAddress.Any, 11000);
// Listen for incoming connections.
listener.Start();
while (true)
{
TcpClient clientRequest;
// Application blocks while waiting for an incoming connection.
// Type CNTL-C to terminate the server.
clientRequest = listener.AcceptTcpClient();
Console.WriteLine("Client connected.");
// A client has connected.
try
{
AuthenticateClient(clientRequest);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
public static void AuthenticateClient(TcpClient clientRequest)
{
NetworkStream stream = clientRequest.GetStream();
// Create the NegotiateStream.
NegotiateStream authStream = new NegotiateStream(stream, false);
// Save the current client and NegotiateStream instance
// in a ClientState object.
ClientState cState = new ClientState(authStream, clientRequest);
// Listen for the client authentication request.
Task authTask = authStream
.AuthenticateAsServerAsync()
.ContinueWith(task => { EndAuthenticateCallback(cState); });
// Any exceptions that occurred during authentication are
// thrown by the EndAuthenticateAsServer method.
try
{
// This call blocks until the authentication is complete.
authTask.Wait();
}
catch (AuthenticationException e)
{
Console.WriteLine(e);
Console.WriteLine("Authentication failed - closing connection.");
return;
}
catch (Exception e)
{
Console.WriteLine(e);
Console.WriteLine("Closing connection.");
return;
}
Task<int> readTask = authStream
.ReadAsync(cState.Buffer, 0, cState.Buffer.Length);
readTask
.ContinueWith((task) => { EndReadCallback(cState, task.Result); })
.Wait();
// Finished with the current client.
authStream.Close();
clientRequest.Close();
}
private static void EndAuthenticateCallback(ClientState cState)
{
// Get the saved data.
NegotiateStream authStream = (NegotiateStream)cState.AuthenticatedStream;
Console.WriteLine("Ending authentication.");
// Display properties of the authenticated client.
IIdentity id = authStream.RemoteIdentity;
Console.WriteLine("{0} was authenticated using {1}.",
id.Name,
id.AuthenticationType
);
}
private static void EndReadCallback(ClientState cState, int bytes)
{
NegotiateStream authStream = (NegotiateStream)cState.AuthenticatedStream;
// Read the client message.
try
{
cState.Message.Append(Encoding.UTF8.GetChars(cState.Buffer, 0, bytes));
if (bytes != 0)
{
Task<int> readTask = authStream.ReadAsync(cState.Buffer, 0, cState.Buffer.Length);
readTask
.ContinueWith(task => { EndReadCallback(cState, task.Result); })
.Wait();
return;
}
}
catch (Exception e)
{
// A real application should do something
// useful here, such as logging the failure.
Console.WriteLine("Client message exception:");
Console.WriteLine(e);
return;
}
IIdentity id = authStream.RemoteIdentity;
Console.WriteLine("{0} says {1}", id.Name, cState.Message.ToString());
}
}
// ClientState is the AsyncState object.
internal class ClientState
{
private StringBuilder _message = null;
internal ClientState(AuthenticatedStream a, TcpClient theClient)
{
AuthenticatedStream = a;
Client = theClient;
}
internal TcpClient Client { get; }
internal AuthenticatedStream AuthenticatedStream { get; }
internal byte[] Buffer { get; } = new byte[2048];
internal StringBuilder Message
{
get { return _message ??= new StringBuilder(); }
}
}
}
注解
使用 NegotiateStream 类进行身份验证,并帮助保护客户端和服务器之间传输的信息。 使用 NegotiateStream,可以执行以下操作。
将客户端的凭据发送到服务器进行模拟或委派。
请求服务器身份验证。
在传输数据之前对其进行加密和/或签名。
在传输信息之前,必须执行身份验证。 客户端使用同步 AuthenticateAsClient 方法(在身份验证完成之前阻止)或异步 BeginAuthenticateAsClient 方法(在等待身份验证完成时不会阻止)来请求身份验证。 服务器使用同步 AuthenticateAsServer 或异步 BeginAuthenticateAsServer 方法请求身份验证。 客户端(可选)使用协商安全协议对服务器进行身份验证。 如果客户端和服务器都支持 Kerberos 协议,则用于身份验证;否则使用 NTLM。 NegotiateStream 类使用安全支持提供程序接口(SSPI)执行身份验证。
身份验证成功后,必须检查 IsEncrypted 和 IsSigned 属性,以确定 NegotiateStream 将使用哪些安全服务来帮助在传输过程中保护数据。 检查 IsMutuallyAuthenticated 属性以确定是否发生了相互身份验证。 可以使用 RemoteIdentity 属性获取有关远程客户端或服务器的信息。
如果身份验证失败,将收到 AuthenticationException 或 InvalidCredentialException。 在这种情况下,可以使用其他凭据重试身份验证。
使用同步 Write 或异步 BeginWrite 或 WriteAsync 方法发送数据。 使用同步 Read 或异步 ReadAsync 或 BeginRead 方法接收数据。 如果启用了加密或签名等安全服务,NegotiateStream会自动将这些服务应用于数据。
NegotiateStream 使用创建 NegotiateStream时提供的流传输数据。 提供此基础流时,可以选择指定是否关闭 NegotiateStream 也会关闭基础流。
构造函数
NegotiateStream(Stream) |
使用指定的 Stream初始化 NegotiateStream 类的新实例。 |
NegotiateStream(Stream, Boolean) |
使用指定的 Stream 和流关闭行为初始化 NegotiateStream 类的新实例。 |
属性
CanRead |
获取一个 Boolean 值,该值指示基础流是否可读。 |
CanSeek |
获取一个 Boolean 值,该值指示基础流是否可查找。 |
CanTimeout |
获取一个 Boolean 值,该值指示基础流是否支持超时。 |
CanWrite |
获取一个 Boolean 值,该值指示基础流是否可写。 |
ImpersonationLevel |
获取一个值,该值指示服务器如何使用客户端的凭据。 |
InnerStream |
获取此 AuthenticatedStream 用于发送和接收数据的流。 (继承自 AuthenticatedStream) |
IsAuthenticated |
获取一个 Boolean 值,该值指示身份验证是否成功。 |
IsEncrypted |
获取一个 Boolean 值,该值指示此 NegotiateStream 是否使用数据加密。 |
IsMutuallyAuthenticated |
获取一个 Boolean 值,该值指示服务器和客户端是否已进行身份验证。 |
IsServer |
获取一个 Boolean 值,该值指示此 NegotiateStream 使用的连接的本地端是否作为服务器进行身份验证。 |
IsSigned |
获取一个 Boolean 值,该值指示是否使用此流发送的数据已签名。 |
LeaveInnerStreamOpen |
获取此 AuthenticatedStream 用于发送和接收数据的流是否已保持打开状态。 (继承自 AuthenticatedStream) |
Length |
获取基础流的长度。 |
Position |
获取或设置基础流中的当前位置。 |
ReadTimeout |
获取或设置读取操作阻止等待数据的时间量。 |
RemoteIdentity |
获取有关共享此经过身份验证流的远程方的标识的信息。 |
WriteTimeout |
获取或设置写入操作阻止等待数据的时间量。 |
方法
扩展方法
CopyToAsync(Stream, PipeWriter, CancellationToken) |
使用取消令牌从 Stream 异步读取字节并将其写入指定的 PipeWriter。 |
ConfigureAwait(IAsyncDisposable, Boolean) |
配置如何执行从异步可释放项返回的任务的 await。 |
适用于
另请参阅
- 对版本 3.5 SP1 中 HTTPWebRequest 的 NTLM 身份验证的更改