HOW TO:指定資料服務要求的用戶端認證 (WCF Data Services)
預設情況下,將要求傳送至 OData 服務時,用戶端程式庫不提供認證。不過,您可以透過為 DataServiceContext 的 Credentials 屬性提供 NetworkCredential,藉以指定要傳送的認證來驗證要求。如需詳細資訊,請參閱保護 WCF Data Services 的安全。本主題中的範例會示範如何在從資料服務要求資料時,明確地提供 WCF Data Services 用戶端所使用的認證。
本主題中的範例使用 Northwind 範例資料服務和自動產生的用戶端資料服務類別。此服務和用戶端資料類別會在您完成 WCF Data Services 快速入門時建立。您也可以使用在 OData 網站上發佈的 Northwind 範例資料服務;此範例資料服務是唯讀的,因此嘗試儲存變更時,會傳回錯誤。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>
安全性
下列安全性考量適用於本主題中的範例:
若要驗證此範例中提供的認證有效,Northwind 資料服務必須使用匿名存取以外的驗證配置。否則,主控資料服務的網站將不會要求認證。
只有在執行期間才會要求使用者認證,而且應該不會快取。認證永遠必須以安全的方式儲存。
使用基本與摘要式驗證傳送的資料不會經過加密,因此敵人可以看到資料。此外,基本驗證認證 (使用者名稱和密碼) 會以純文字傳送,而且可以被攔截。
如需詳細資訊,請參閱保護 WCF Data Services 的安全。