다음을 통해 공유


방법: 데이터 서비스 요청에 대한 클라이언트 자격 증명 지정(Silverlight 클라이언트)

Open Data Protocol(OData)을 구현하는 데이터 서비스에 대한 요청을 수행할 때 사용되는 자격 증명을 지정할 수 있습니다. 이렇게 하려면 도메인 간 요청을 수행하거나, 브라우저 외부에서 실행하거나, HttpStack 속성의 값을 ClientHttp로 명시적으로 설정해야 합니다. 이러한 경우 자격 증명 캐시의 기본 자격 증명이 사용됩니다. 또한 UseDefaultCredentials 속성을 false로 설정하고 DataServiceContextCredentials 속성에 대해 NetworkCredential을 제공하여 기본값이 아닌 자격 증명을 제공할 수도 있습니다. 이 항목의 예제는 데이터 서비스의 데이터를 요청할 때 Silverlight 클라이언트에 사용되는 자격 증명을 명시적으로 제공하는 방법을 나타냅니다.

WCF Data Services 퀵 스타트를 완료하면 응용 프로그램에서 액세스된 Northwind 샘플 데이터 서비스가 만들어집니다. OData 웹 사이트에 게시된 공용 Northwind 샘플 데이터 서비스를 사용할 수도 있습니다. 이 샘플 데이터 서비스는 읽기 전용이므로 변경 내용을 저장하려고 하면 오류가 발생합니다.

다음 예제는 Silverlight 응용 프로그램의 기본 페이지인 XAML(Extensible Application Markup Language) 파일에 대한 코드 숨김 페이지에서 가져온 것입니다. 이 예제는 사용자의 인증 자격 증명을 수집한 다음 Silverlight 클라이언트 HTTP 구현을 사용하여 데이터 서비스에 요청을 수행할 때 기본값이 아닌 자격 증명을 사용하는 LoginWindow 인스턴스를 보여 줍니다.

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();
            }
        }
    }
}

다음 XAML에서는 Silverlight 응용 프로그램의 기본 페이지를 정의합니다.

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

다음 예제는 데이터 서비스에 요청을 하기 전에 인증 자격 증명을 수집하는 데 사용되는 ChildWindow의 코드 숨김 페이지에서 가져온 것입니다.

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();
            }
        }

    }
}

다음 XAML은 Silverlight 응용 프로그램의 ChildWindow인 로그인 창을 정의합니다.

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

보안

이 항목의 예제에는 다음과 같은 보안 고려 사항이 적용됩니다.

  • 이 예제에 제공된 자격 증명이 작동하는지 확인하려면 Northwind 데이터 서비스에서 익명 액세스 외의 다른 인증 체계를 사용해야 합니다. 그렇지 않으면 데이터 서비스를 호스팅하는 웹 사이트에서 자격 증명을 요청하지 않습니다.

  • 사용자 자격 증명은 실행 중에만 요청되어야 하며 캐시되어서는 안 됩니다. 자격 증명은 항상 안전하게 보관해야 합니다.

  • 기본 및 다이제스트 인증과 함께 전송된 데이터는 암호화되지 않으므로 악의적 사용자가 데이터를 볼 수 있습니다. 또한 기본 인증 자격 증명(사용자 이름 및 암호)은 일반 텍스트로 보내지므로 누군가 이를 가로챌 수 있습니다.

참고 항목

개념

Silverlight 응용 프로그램 만들기(WCF Data Services)

관련 자료

WCF Data Services Tasks for Silverlight

Security