Share via


如何:为数据服务请求(WCF 数据服务)指定客户端凭据

默认情况下,客户端库在向 OData 服务发送请求时不提供凭据。 但是,可以通过为 DataServiceContextCredentials 属性提供 NetworkCredential 以指定发送凭据,对发送到数据服务的请求进行身份验证。 有关更多信息,请参见 WCF 数据服务的安全。 本主题中的示例揭示了如何显式提供 WCF 数据服务客户端从数据服务请求数据时使用的凭据。

本主题中的示例使用 Northwind 示例数据服务和自动生成的客户端数据服务类。 此服务和这些客户端数据类是在完成 WCF 数据服务快速入门时创建的。 还可以使用 OData 网站上发布的罗斯文示例数据服务;该示例数据服务是只读的,它会尝试保存更改并返回错误。 OData 网站上的示例数据服务允许进行匿名身份验证。

示例

以下示例来自 Windows Presentation Framework 应用程序的可扩展应用程序标记语言 (XAML) 主页文件的代码隐藏页。 该示例显示了一个 LoginWindow 实例,用于收集用户的身份验证凭据,然后在向数据服务发出请求时使用了这些凭据。

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.");
            }
        }
    }
}

以下 XAML 定义了 WPF 应用程序的主页。

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

以下示例来自窗口的代码隐藏页,该窗口用于在向数据服务发出请求时收集用户的身份验证凭据。

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.");
            }
        }

    }
}

以下 XAML 定义了 WPF 应用程序的登录。

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

安全性

本主题中的示例适用以下安全注意事项:

  • 为验证此示例中提供的凭据是否能够正常工作,罗斯文数据服务必须使用一种非匿名访问的身份验证方案。 否则,承载数据服务的网站将不会请求凭据。

  • 用户凭据应仅在执行过程中请求并且不应缓存。 必须始终安全地存储凭据。

  • 使用基本和摘要式身份验证发送的数据不会加密,因此敌对方会看到数据。 此外,基本身份验证凭据(用户名和密码)是以明文形式发送的,会被截取。

有关更多信息,请参见 WCF 数据服务的安全

请参阅

概念

WCF 数据服务的安全

其他资源

数据客户端 (WCF Data Services)