Freigeben über


Vorgehensweise: Angeben von Clientanmeldeinformationen für eine Datendienstanforderung (Silverlight-Client)

Sie können die Anmeldeinformationen angeben, die für eine Anforderung an einen Datendienst, der Open Data Protocol (OData) implementiert, verwendet werden sollen. Hierzu müssen Sie eine domänenübergreifende Anforderung ausführen, die Anwendung außerhalb des Browsers ausführen oder den Wert der HttpStack-Eigenschaft explizit auf ClientHttp festlegen. In diesen Fällen werden die Standardanmeldeinformationen aus dem Cache für Anmeldeinformationen verwendet. Sie können auch andere als die Standardanmeldeinformationen angeben, indem Sie die UseDefaultCredentials-Eigenschaft auf false festlegen und ein NetworkCredential für die Credentials-Eigenschaft des DataServiceContext bereitstellen. Das Beispiel in diesem Thema veranschaulicht das explizite Angeben von Anmeldeinformationen, die beim Anfordern von Daten vom Datendienst vom Silverlight-Client verwendet werden.

Der Northwind-Beispieldatendienst, auf den die Anwendung zugreift, wird erstellt, wenn Sie den WCF Data Services-Schnellstart abschließen. Sie können auch den öffentlichen Northwind-Beispieldatendienst auf der OData-Website verwenden. Dieser Beispieldatendienst ist schreibgeschützt. Wenn Sie versuchen, Änderungen zu speichern, wird ein Fehler zurückgegeben.

Beispiel

Das folgende Beispiel stammt aus der CodeBehind-Seite für eine XAML (Extensible Application Markup Language)-Datei, bei der es sich um die Hauptseite der Silverlight-Anwendung handelt. In diesem Beispiel werden mit einer LoginWindow-Instanz Anmeldeinformationen für die Authentifizierung vom Benutzer gesammelt, die dann beim Senden einer Datendienstanforderung mit der HTTP-Implementierung des Silverlight-Clients verwendet werden.

Imports ClientCredentials.Northwind
Imports System.Data.Services.Client
Imports System.Windows.Data
Imports System.Net

Partial Public Class MainPage
    Inherits UserControl

    ' 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 MainPage_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)

        ' Get credentials for authentication.
        Dim login As LoginWindow = New LoginWindow()
        AddHandler login.Closed, AddressOf loginWindow_Closed
        login.Show()
    End Sub

    Private Sub loginWindow_Closed(ByVal sender As Object, ByVal e As EventArgs)
        Dim userName = String.Empty
        Dim domain = String.Empty
        Dim password = String.Empty

        ' Get back the LoginWindow instance.
        Dim login As LoginWindow = CType(sender, LoginWindow)

        If login.DialogResult = True AndAlso Not login.userNameBox.Text Is String.Empty Then

            ' Instantiate the binding collection.
            binding = New DataServiceCollection(Of Customer)()

            ' Instantiate the context.
            context = New NorthwindEntities(serviceUri)

            ' Register the LoadCompleted event for the binding collection.
            AddHandler binding.LoadCompleted, AddressOf binding_LoadCompleted

            ' 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

            ' 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.Password

            ' Select the client HTTP stack and set the credentials.
            context.HttpStack = HttpStack.ClientHttp
            context.UseDefaultCredentials = False
            context.Credentials = _
                New NetworkCredential(userName, password, domain)

            Try
                ' Execute the query asynchronously.
                binding.LoadAsync(query)
            Catch ex As Exception
                Dim cw = New ChildWindow()
                cw.Content = ex.Message
                cw.Show()
            End Try
        ElseIf login.DialogResult = False Then        
            Dim cw = New ChildWindow()
            cw.Content = "Login cancelled."
            cw.Show()
        End If
    End Sub
    Private Sub binding_LoadCompleted(ByVal sender As Object, ByVal e As LoadCompletedEventArgs)
        If e.Error Is Nothing Then
            serviceUriLabel.Content = serviceUri.ToString()

            ' Load all pages of Customers before binding.
            If Not binding.Continuation Is Nothing Then
                binding.LoadNextPartialSetAsync()
            Else
                ' Load your data here and assign the result to the CollectionViewSource.
                customerAddressViewSource = _
                    CType(Me.Resources("customerViewSource"), CollectionViewSource)
                customerAddressViewSource.Source = binding
            End If
        Else

            ' Display the error message from the data service.
            Dim cw = New ChildWindow()
            cw.Content = e.Error.Message
            cw.Show()
        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 ClientCredentials.Northwind;
using System.Data.Services.Client;

namespace ClientCredentials
{
    public partial class MainPage : UserControl
    {
        // 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 MainPage()
        {
            InitializeComponent();
        }

        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            // Get credentials for authentication.
            LoginWindow login = new LoginWindow();
            login.Closed += new EventHandler(loginWindow_Closed);
            login.Show();
        }

        private void loginWindow_Closed(object sender, EventArgs e)
        {
            string userName = string.Empty;
            string domain = string.Empty;
            string password = string.Empty;

            // Get back the LoginWindow instance.
            LoginWindow login = (LoginWindow)sender;

            if (login.DialogResult == true && login.userNameBox.Text != string.Empty)
            {
                // Instantiate the binding collection.
                binding = new DataServiceCollection<Customer>();

                // Instantiate the context.
                context =
                    new NorthwindEntities(serviceUri);

                // Register the LoadCompleted event for the binding collection.
                binding.LoadCompleted += new EventHandler<LoadCompletedEventArgs>(binding_LoadCompleted);

                // 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;


                // 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.Password;

                // Select the client HTTP stack and set the credentials.
                context.HttpStack = HttpStack.ClientHttp;
                context.UseDefaultCredentials = false;
                context.Credentials = 
                    new NetworkCredential(userName, password, domain);

                try
                {
                    // Execute the query asynchronously.
                    binding.LoadAsync(query);
                }
                catch (Exception ex)
                {
                    ChildWindow cw = new ChildWindow();
                    cw.Content = ex.Message;
                    cw.Show();
                }
            }
            else if (login.DialogResult == false)
            {
                ChildWindow cw = new ChildWindow();
                cw.Content = "Login cancelled.";
                cw.Show();
            }
        }

        private void binding_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                serviceUriLabel.Content = serviceUri.ToString();

                // Load all pages of Customers before binding.
                if (binding.Continuation != null)
                {
                    binding.LoadNextPartialSetAsync();
                }
                else
                {
                    // Load your data here and assign the result to the CollectionViewSource.
                    customerAddressViewSource =
                        (CollectionViewSource)this.Resources["customerViewSource"];
                    customerAddressViewSource.Source = binding;
                }
            }
            else
            {
                // Display the error message from the data service.
                ChildWindow cw = new ChildWindow();
                cw.Content = e.Error.Message;
                cw.Show();
            }
        }
    }
}

Der folgende XAML-Code definiert die Hauptseite der Silverlight-Anwendung.

    <UserControl x:Class="ClientCredentials.MainPage"
    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" 
             xmlns:sdk="https://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
             xmlns:my="clr-namespace:ClientCredentials" Loaded="MainPage_Loaded">
    <UserControl.Resources>
        <CollectionViewSource x:Key="customerViewSource" 
                              d:DesignSource="{d:DesignInstance my:Northwind.Customer, CreateList=True}" />
    </UserControl.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>
        <sdk: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">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn x:Name="customerIDColumn" Binding="{Binding Path=CustomerID}" 
                                        Header="Customer" Width="80" />
                <sdk:DataGridTextColumn x:Name="addressColumn" Binding="{Binding Path=Address}" 
                                        Header="Address" Width="180" />
                <sdk:DataGridTextColumn x:Name="cityColumn" Binding="{Binding Path=City}" 
                                        Header="City" Width="120" />
                <sdk:DataGridTextColumn x:Name="countryColumn" Binding="{Binding Path=Country}" 
                                        Header="Country" Width="80" />
                <sdk:DataGridTextColumn x:Name="postalCodeColumn" Binding="{Binding Path=PostalCode}" 
                                        Header="Postal Code" Width="90" />
                <sdk:DataGridTextColumn Binding="{Binding Path=CompanyName}" Header="CompanyName" />
                <sdk:DataGridTextColumn Binding="{Binding Path=ContactName}" Header="ContactName" />
                <sdk:DataGridTextColumn Binding="{Binding Path=Phone}" Header="Phone" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
        <sdk:Label Grid.Row="0" Grid.Column="0" Height="26" HorizontalAlignment="Left" Margin="16,12,0,0" 
                   Name="serviceUriLabel" VerticalAlignment="Top" Width="550"  />
    </Grid>
</UserControl>

Das folgende Beispiel stammt aus der CodeBehind-Seite für ChildWindow, mit dem die Anmeldeinformationen für die Authentifizierung vom Benutzer gesammelt werden, bevor eine Anforderung an den Datendienst gesendet wird.

Imports System.ComponentModel

Partial Public Class LoginWindow
    Inherits ChildWindow

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub OKButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles OKButton.Click
        Me.DialogResult = True
    End Sub

    Private Sub CancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles CancelButton.Click
        Me.DialogResult = False
    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.Password = String.Empty) Then
            e.Cancel = True
            Dim cw As ChildWindow = New ChildWindow()
            cw.Content = "Please enter name and password or click Cancel."
            cw.Show()
        End If
    End Sub
End Class
using System;
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;

namespace ClientCredentials
{
    public partial class LoginWindow : ChildWindow
    {
        public LoginWindow()
        {
            InitializeComponent();
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }

        private void CancelButton_Click(object sender, RoutedEventArgs e)
        {
             this.DialogResult = false;
        }

        private void LoginWindow_Closing(object sender, CancelEventArgs e)
        {
            if (this.DialogResult == true &&
                    (this.userNameBox.Text == string.Empty || this.passwordBox.Password == string.Empty))
            {
                e.Cancel = true;
                ChildWindow cw = new ChildWindow();
                cw.Content = "Please enter name and password or click Cancel.";
                cw.Show();
            }
        }

    }
}

Der folgende XAML-Code definiert das Anmeldefenster, bei dem es sich um ein ChildWindow der Silverlight-Anwendung handelt.

    <controls:ChildWindow x:Class="ClientCredentials.LoginWindow"
           xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           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" />
            <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" 
                HorizontalAlignment="Right" Margin="8" />
        </StackPanel>
    </StackPanel>
</controls:ChildWindow>

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.

Siehe auch

Konzepte

Erstellen von Silverlight-Anwendungen (WCF Data Services)

Andere Ressourcen

WCF Data Services Tasks for Silverlight

Security