Vorgehensweise: Angeben von Clientanmeldeinformationen für eine Datendienstanforderung (WCF Data Services)
In der Standardeinstellung werden von der Clientbibliothek keine Anmeldeinformationen bereitgestellt, wenn eine Anforderung an einen OData -Dienst gesendet wird. Sie können jedoch angeben, dass Anmeldeinformationen zum Authentifizieren von Anforderungen an den Datendienst gesendet werden, indem Sie NetworkCredential für die Credentials-Eigenschaft des DataServiceContext angeben. Weitere Informationen finden Sie unter Sichern von WCF Data Services. Das Beispiel in diesem Thema veranschaulicht das explizite Angeben von Anmeldeinformationen, die beim Anfordern von Daten vom Datendienst vom WCF Data Services -Client verwendet werden.
Im Beispiel in diesem Thema werden der Northwind-Beispieldatendienst und automatisch generierte Client-Datendienstklassen verwendet. Dieser Dienst und die Clientdatenklassen werden erstellt, wenn Sie den WCF Data Services-Schnellstart ausführen. Sie können auch den auf der OData -Website veröffentlichten Northwind-Beispieldatendienst verwenden. Dieser Beispieldatendienst ist schreibgeschützt. Wenn Sie versuchen, Änderungen zu speichern, wird ein Fehler zurückgegeben. Die Beispieldatendienste auf der OData -Website lassen die anonyme Authentifizierung zu.
Beispiel
Das folgende Beispiel stammt aus der CodeBehind-Seite für eine XAML-Datei (Extensible Application Markup Language), bei der es sich um die Hauptseite der Windows Presentation Framework-Anwendung handelt. In diesem Beispiel werden mit einer LoginWindow-Instanz Anmeldeinformationen für die Authentifizierung vom Benutzer gesammelt, die dann beim Senden einer Anforderung an den Datendienst verwendet werden.
Imports NorthwindClient.Northwind
Imports System.Data.Services.Client
Imports System.Windows.Data
Imports System.Net
Imports System.Windows
Imports System.Security
Partial Public Class ClientCredentials
Inherits Window
' Create the binding collections and the data service context.
Private binding As DataServiceCollection(Of Customer)
Private context As NorthwindEntities
Private customerAddressViewSource As CollectionViewSource
' Instantiate the service URI and credentials.
Dim serviceUri As Uri = New Uri("https://localhost:54321/Northwind.svc/")
Private credentials As NetworkCredential = New NetworkCredential()
Public Sub Main()
InitializeComponent()
End Sub
Private Sub ClientCredentials_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim userName = String.Empty
Dim domain = String.Empty
Dim password = New SecureString()
' Get credentials for authentication.
Dim login As New LoginWindow()
login.ShowDialog()
If login.DialogResult = True _
AndAlso Not login.userNameBox.Text Is String.Empty _
AndAlso login.passwordBox.SecurePassword.Length <> 0 Then
' Instantiate the context.
context = New NorthwindEntities(serviceUri)
' Get the user name and domain from the login.
Dim qualifiedUserName As String() = login.userNameBox.Text.Split(New [Char]() {"\"c})
If qualifiedUserName.Length = 2 Then
domain = qualifiedUserName(0)
userName = qualifiedUserName(1)
Else
userName = login.userNameBox.Text
End If
password = login.passwordBox.SecurePassword
' Set the client authentication credentials.
context.Credentials = _
New NetworkCredential(userName, password, domain)
' Define an anonymous LINQ query that returns a collection of Customer types.
Dim query = From c In context.Customers
Where c.Country = "Germany"
Select c
Try
' Instantiate the binding collection, which executes the query.
binding = New DataServiceCollection(Of Customer)(query)
' Load result pages into the binding collection.
While Not binding.Continuation Is Nothing
' Continue to execute the query until all pages are loaded.
binding.Load(context.Execute(Of Customer)(binding.Continuation.NextLinkUri))
End While
' Assign the binding collection to the CollectionViewSource.
customerAddressViewSource = _
CType(Me.Resources("customerViewSource"), CollectionViewSource)
customerAddressViewSource.Source = binding
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
ElseIf login.DialogResult = False Then
MessageBox.Show("Login cancelled.")
End If
End Sub
End Class
using System;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Security;
using NorthwindClient.Northwind;
using System.Data.Services.Client;
namespace NorthwindClient
{
public partial class ClientCredentials : Window
{
// Create the binding collections and the data service context.
private DataServiceCollection<Customer> binding;
NorthwindEntities context;
CollectionViewSource customerAddressViewSource;
// Instantiate the service URI and credentials.
Uri serviceUri = new Uri("https://localhost:12345/Northwind.svc/");
NetworkCredential credentials = new NetworkCredential();
public ClientCredentials()
{
InitializeComponent();
}
private void ClientCredentials_Loaded(object sender, RoutedEventArgs e)
{
string userName = string.Empty;
string domain = string.Empty;
SecureString password = new SecureString();
// Get credentials for authentication.
LoginWindow login = new LoginWindow();
login.ShowDialog();
if (login.DialogResult == true
&& login.userNameBox.Text != string.Empty
&& login.passwordBox.SecurePassword.Length != 0)
{
// Instantiate the context.
context =
new NorthwindEntities(serviceUri);
// Get the user name and domain from the login.
string[] qualifiedUserName = login.userNameBox.Text.Split(new char[] { '\\' });
if (qualifiedUserName.Length == 2)
{
domain = qualifiedUserName[0];
userName = qualifiedUserName[1];
}
else
{
userName = login.userNameBox.Text;
}
password = login.passwordBox.SecurePassword;
// Set the client authentication credentials.
context.Credentials =
new NetworkCredential(userName, password, domain);
// Define an anonymous LINQ query that returns a collection of Customer types.
var query = from c in context.Customers
where c.Country == "Germany"
select c;
try
{
// Instantiate the binding collection, which executes the query.
binding = new DataServiceCollection<Customer>(query);
while (binding.Continuation != null)
{
// Continue to execute the query until all pages are loaded.
binding.Load(context.Execute<Customer>(binding.Continuation.NextLinkUri));
}
// Assign the binding collection to the CollectionViewSource.
customerAddressViewSource =
(CollectionViewSource)this.Resources["customerViewSource"];
customerAddressViewSource.Source = binding;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
else if (login.DialogResult == false)
{
MessageBox.Show("Login cancelled.");
}
}
}
}
Der folgende XAML-Code definiert die Hauptseite der WPF-Anwendung.
<Window x:Class="ClientCredentials"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="312" d:DesignWidth="577"
Loaded="ClientCredentials_Loaded">
<Window.Resources>
<CollectionViewSource x:Key="customerViewSource" />
</Window.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="" Height="312" Width="577"
VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid.RowDefinitions>
<RowDefinition Height="203*" />
<RowDefinition Height="119*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="336*" />
</Grid.ColumnDefinitions>
<DataGrid AutoGenerateColumns="False" Height="213" HorizontalAlignment="Left"
ItemsSource="{Binding Source={StaticResource customerViewSource}}"
Name="customerDataGrid" RowDetailsVisibilityMode="VisibleWhenSelected"
VerticalAlignment="Top" Width="553" Margin="12,44,0,0"
Grid.RowSpan="2" Grid.ColumnSpan="1">
<DataGrid.Columns>
<DataGridTextColumn x:Name="customerIDColumn" Binding="{Binding Path=CustomerID}"
Header="Customer" Width="80" />
<DataGridTextColumn x:Name="addressColumn" Binding="{Binding Path=Address}"
Header="Address" Width="180" />
<DataGridTextColumn x:Name="cityColumn" Binding="{Binding Path=City}"
Header="City" Width="120" />
<DataGridTextColumn x:Name="countryColumn" Binding="{Binding Path=Country}"
Header="Country" Width="80" />
<DataGridTextColumn x:Name="postalCodeColumn" Binding="{Binding Path=PostalCode}"
Header="Postal Code" Width="90" />
<DataGridTextColumn Binding="{Binding Path=CompanyName}" Header="CompanyName" />
<DataGridTextColumn Binding="{Binding Path=ContactName}" Header="ContactName" />
<DataGridTextColumn Binding="{Binding Path=Phone}" Header="Phone" />
</DataGrid.Columns>
</DataGrid>
<Label Grid.Row="0" Grid.Column="0" Height="26" HorizontalAlignment="Left" Margin="16,12,0,0"
Name="serviceUriLabel" VerticalAlignment="Top" Width="550" />
</Grid>
</Window>
Das folgende Beispiel stammt aus der CodeBehind-Seite für das Fenster, mit dem die Anmeldeinformationen für die Authentifizierung vom Benutzer gesammelt werden, bevor eine Anforderung an den Datendienst gesendet wird.
Imports System.ComponentModel
Imports System.Windows
Imports System.Security
Partial Public Class LoginWindow
Inherits Window
Public Sub New()
InitializeComponent()
End Sub
Private Sub OKButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles OKButton.Click
Me.DialogResult = True
e.Handled = True
End Sub
Private Sub CancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles CancelButton.Click
Me.DialogResult = False
e.Handled = True
End Sub
Private Sub LoginWindow_Closing(ByVal sender As System.Object, ByVal e As CancelEventArgs)
If Me.DialogResult = True AndAlso _
(Me.userNameBox.Text = String.Empty OrElse Me.passwordBox.SecurePassword.Length = 0) Then
e.Cancel = True
MessageBox.Show("Please enter name and password or click Cancel.")
End If
End Sub
End Class
using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
namespace NorthwindClient
{
public partial class LoginWindow : Window
{
public LoginWindow()
{
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
e.Handled = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
e.Handled = true;
}
private void LoginWindow_Closing(object sender, CancelEventArgs e)
{
if (this.DialogResult == true &&
(this.userNameBox.Text == string.Empty || this.passwordBox.SecurePassword.Length == 0))
{
e.Cancel = true;
MessageBox.Show("Please enter name and password or click Cancel.");
}
}
}
}
Der folgende XAML-Code definiert das Anmeldefenster der WPF-Anwendung.
<Window x:Class="LoginWindow"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="200"
Title="LoginWindow" xmlns:sdk="https://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" Closing="LoginWindow_Closing">
<StackPanel Name="LayoutRoot" Orientation="Vertical" VerticalAlignment="Top">
<StackPanel Orientation="Horizontal">
<TextBlock Height="25" HorizontalAlignment="Left" Margin="10,20,0,0" Name="userNameLabel" VerticalAlignment="Top"
Width="80" Text="User name:"/>
<TextBox Height="23" HorizontalAlignment="Left" Margin="10,20,0,0" Name="userNameBox" VerticalAlignment="Top"
Width="150" Text="DOMAIN\login"/>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<TextBlock Height="25" HorizontalAlignment="Left" Margin="10,20,0,0" Name="pwdLabel" Width="80" Text="Password:"/>
<PasswordBox Height="23" HorizontalAlignment="Left" Margin="10,20,0,0" Name="passwordBox" Width="150" />
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Height="80" VerticalAlignment="Top">
<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23"
HorizontalAlignment="Right" Margin="8" IsCancel="True" />
<Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23"
HorizontalAlignment="Right" Margin="8" IsDefault="True" />
</StackPanel>
</StackPanel>
</Window>
Sicherheit
Die folgenden Überlegungen zur Sicherheit gelten für das Beispiel in diesem Thema:
Um zu überprüfen, ob die angegebenen Anmeldeinformationen in diesem Beispiel funktionieren, muss für den Northwind-Datendienst ein anderes Authentifizierungsschema als der anonyme Zugriff verwendet werden. Andernfalls werden von der Website, die den Datendienst hostet, keine Anmeldeinformationen angefordert.
Benutzeranmeldeinformationen sollten nur während der Ausführung angefordert und nicht zwischengespeichert werden. Anmeldeinformationen müssen immer sicher gespeichert werden.
Mittels Standard- und Digestauthentifizierung gesendete Daten sind nicht verschlüsselt und daher für Angreifer sichtbar. Anmeldeinformationen für die Standardauthentifizierung (Benutzername und Kennwort) werden zudem in Klartext gesendet und können abgefangen werden.
Weitere Informationen finden Sie unter Sichern von WCF Data Services.