NegotiateStream 類別
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
提供數據流,以使用交涉安全性通訊協議來驗證用戶端,以及選擇性地在用戶端與伺服器通訊中。
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) |
設定如何執行從異步可處置專案傳回的工作等候。 |
適用於
另請參閱
- 3.5 SP1 版中 HTTPWebRequest 的 NTLM 驗證變更