연습: 클라이언트 응용 프로그램 서비스 사용

이 항목에서는 클라이언트 응용 프로그램 서비스를 사용하여 사용자를 인증하고 사용자 역할과 설정을 검색하는 Windows 응용 프로그램을 만드는 방법에 대해 설명합니다.

이 연습에서는 다음 작업을 수행합니다.

  • Windows Forms 응용 프로그램을 만들고 Visual Studio 프로젝트 디자이너를 사용하여 클라이언트 응용 프로그램 서비스를 활성화 및 구성합니다.

  • 간단한 ASP.NET 웹 서비스 응용 프로그램을 만들어 응용 프로그램 서비스를 호스팅하고 클라이언트 구성을 테스트합니다.

  • 응용 프로그램에 폼 인증을 추가합니다. 이를 위해 먼저 하드 코드된 사용자 이름과 암호를 사용하여 서비스를 테스트합니다. 그런 다음 응용 프로그램 구성에서 로그인 폼을 자격 증명 공급자로 지정하여 해당 폼을 추가합니다.

  • "관리자" 역할에 있는 사용자에게만 단추를 활성화하고 표시하여 역할 기반 기능을 추가합니다.

  • 웹 설정에 액세스합니다. 이를 위해 먼저 프로젝트 디자이너의 설정 페이지에서 인증된(테스트된) 사용자에 대한 웹 설정을 로드합니다. 그런 다음 Windows Forms 디자이너를 사용하여 텍스트 상자를 웹 설정에 바인딩합니다. 마지막으로 수정된 값을 다시 서버에 저장합니다.

  • 로그아웃을 구현합니다. 로그아웃 옵션을 폼에 추가하고 로그아웃 메서드를 호출합니다.

  • 오프라인 모드를 활성화합니다. 사용자가 연결 상태를 지정할 수 있도록 확인란을 제공합니다. 그런 다음 이 값을 사용하여 클라이언트 응용 프로그램 서비스에서 해당 웹 서비스 대신 로컬로 캐시된 데이터를 사용할 것인지 여부를 지정합니다. 마지막으로 응용 프로그램이 온라인 모드로 돌아가면 현재 사용자를 다시 인증합니다.

사전 요구 사항

이 연습을 완료하려면 다음 구성 요소가 필요합니다.

  • Visual Studio 2008.

클라이언트 응용 프로그램 만들기

먼저 해야 할 일은 Windows Forms 프로젝트를 만드는 것입니다. 이 연습에서는 많은 사람들이 익숙하게 느끼는 Windows Forms를 사용하지만 프로세스는 오히려 WPF(Windows Presentation Foundation) 프로젝트와 비슷합니다.

클라이언트 응용 프로그램을 만들고 클라이언트 응용 프로그램 서비스를 활성화하려면

  1. Visual Studio에서 파일 | 새로 만들기 | 프로젝트 메뉴 옵션을 선택합니다.

  2. 새 프로젝트 대화 상자의 프로젝트 형식 창에서 Visual Basic 또는 Visual C# 노드를 확장하고 Windows 프로젝트 형식을 선택합니다.

  3. .NET Framework 3.5가 선택되어 있는지 확인한 다음 Windows Forms 응용 프로그램 템플릿을 선택합니다.

  4. 프로젝트 이름을 ClientAppServicesDemo로 변경한 다음 확인을 클릭합니다.

    Visual Studio에서 새 Windows Forms 프로젝트가 열립니다.

  5. 프로젝트 메뉴에서 ClientAppServicesDemo 속성을 선택합니다.

    프로젝트 디자이너가 나타납니다.

  6. 서비스 탭에서 클라이언트 응용 프로그램 서비스 사용을 선택합니다.

  7. 폼 인증 사용이 선택되어 있는지 확인한 다음 인증 서비스 위치, 역할 서비스 위치웹 설정 서비스 위치를 https://localhost:55555/AppServices로 설정합니다.

  8. Visual Basic의 응용 프로그램 탭에서 인증 모드응용 프로그램 정의로 설정합니다.

지정된 설정이 응용 프로그램의 app.config 파일에 저장됩니다.

이때 세 개의 모든 서비스를 동일한 호스트에서 액세스하도록 응용 프로그램이 구성됩니다. 다음 단원에서는 클라이언트 구성을 테스트할 수 있도록 간단한 웹 서비스 응용 프로그램을 호스트로 만듭니다.

응용 프로그램 서비스 호스트 만들기

이 단원에서는 로컬 SQL Server Compact 3.5 데이터베이스 파일에서 사용자 데이터에 액세스하는 간단한 웹 서비스 응용 프로그램을 만들고 ASP.NET 웹 사이트 관리 도구를 사용하여 이 데이터베이스를 채웁니다. 이 간단한 구성을 사용하여 클라이언트 응용 프로그램을 빠르게 테스트할 수 있습니다. 전체 SQL Server 데이터베이스 또는 사용자 지정 MembershipProviderRoleProvider 클래스를 통해 사용자 데이터에 액세스하도록 웹 서비스 호스트를 구성할 수도 있습니다. 자세한 내용은 SQL Server용 응용 프로그램 서비스 데이터베이스 만들기 및 구성을 참조하십시오.

다음 절차에서는 AppServices 웹 서비스를 만들고 구성합니다.

응용 프로그램 서비스 호스트를 만들고 구성하려면

  1. 솔루션 탐색기에서 ClientAppServicesDemo 솔루션을 선택한 다음 파일 메뉴에서 추가 | 새 프로젝트를 선택합니다.

  2. 새 프로젝트 추가 대화 상자의 프로젝트 형식 창에서 Visual Basic 또는 Visual C# 노드를 확장하고 프로젝트 형식을 선택합니다.

  3. .NET Framework 3.5가 선택되어 있는지 확인한 다음 ASP.NET 웹 서비스 응용 프로그램 템플릿을 선택합니다.

  4. 프로젝트 이름을 AppServices로 변경한 다음 확인을 클릭합니다.

    새 ASP.NET 웹 서비스 응용 프로그램 프로젝트가 솔루션에 추가되고 Service1.asmx.vb 또는 Service1.asmx.cs 파일이 편집기에 표시됩니다.

    참고

    Service1.asmx.vb 또는 Service1.asmx.cs 파일은 이 예제에서 사용되지 않습니다. 작업 환경을 정리된 상태로 유지하고 싶으면 해당 파일을 닫은 다음 솔루션 탐색기에서 삭제할 수 있습니다.

  5. 솔루션 탐색기에서 AppServices 프로젝트를 선택하고 프로젝트 메뉴에서 AppServices 속성을 클릭합니다.

    프로젝트 디자이너가 나타납니다.

  6. 탭에서 Visual Studio 개발 서버 사용이 선택되어 있는지 확인합니다.

  7. 특정 포트를 선택하고 값으로 55555를 지정한 다음 가상 경로를 /AppServices로 설정합니다.

  8. 모든 파일을 저장합니다.

  9. 솔루션 탐색기에서 Web.config를 열고 여는 <system.web> 태그를 찾습니다.

  10. 다음 태그를 <system.web> 태그 앞에 추가합니다.

    이 태그의 authenticationService, profileService 및 roleService 요소는 응용 프로그램 서비스를 활성화 및 구성합니다. 테스트를 위해 authenticationService 요소의 requireSSL 특성은 "false"로 설정되어 있습니다. profileService 요소의 readAccessProperties 및 writeAccessProperties 특성은 WebSettingsTestText 속성이 읽기/쓰기가 가능하다는 것을 나타냅니다.

    참고

    프로덕션 코드에서는 항상 SSL(Secure Sockets Layer) 및 HTTPS 프로토콜을 사용하여 인증 서비스에 액세스해야 합니다. SSL을 설정하는 방법에 대한 자세한 내용은 Configuring Secure Sockets Layer (IIS 6.0 Operations Guide)를 참조하십시오.

    <system.web.extensions>
      <scripting>
        <webServices>
          <authenticationService enabled="true" requireSSL = "false"/>
          <profileService enabled="true"
            readAccessProperties="WebSettingsTestText"
            writeAccessProperties="WebSettingsTestText" />
          <roleService enabled="true"/>
        </webServices>
      </scripting>
    </system.web.extensions>
    
  11. 다음 태그를 여는 <system.web> 태그 뒤에 추가하여 <system.web> 요소 내에 포함되도록 합니다.

    profile 요소는 WebSettingsTestText라는 단일 웹 설정을 구성합니다.

    <profile enabled="true" >
      <properties>
        <add name="WebSettingsTestText" type="string" 
          readOnly="false" defaultValue="DefaultText" 
          serializeAs="String" allowAnonymous="false" />
      </properties>
    </profile>
    

다음 절차에서는 ASP.NET 웹 사이트 관리 도구를 사용하여 서비스 구성을 완료하고 로컬 데이터베이스 파일을 채웁니다. 각각 사용자 이름과 동일한 이름의 역할에 속해 있는 employee와 manager라는 두 사용자를 추가합니다. 사용자 암호는 각각 employee!와 manager!입니다.

멤버 자격 및 역할을 구성하려면

  1. 솔루션 탐색기에서 AppServices 프로젝트를 선택한 다음 프로젝트 메뉴에서 ASP.NET 구성을 선택합니다.

    ASP.NET 웹 사이트 관리 도구가 나타납니다.

  2. 보안 탭에서 **보안 설정 마법사를 사용하여 보안을 단계별로 구성하십시오.**를 클릭합니다.

    보안 설정 마법사가 시작되면서 시작 단계가 표시됩니다.

  3. 다음을 클릭합니다.

    액세스 방법 선택 단계가 표시됩니다.

  4. 인터넷을 선택합니다. 이렇게 하면 서비스가 Windows 인증 대신 폼 인증을 사용하도록 구성됩니다.

  5. 다음을 두 번 클릭합니다.

    역할 정의 단계가 표시됩니다.

  6. **이 웹 사이트에 역할을 사용하도록 설정합니다.**를 선택합니다.

  7. 다음을 클릭합니다. 새 역할 만들기 폼이 표시됩니다.

  8. 새 역할 이름 텍스트 상자에 manager를 입력한 다음 역할 추가를 클릭합니다.

    지정된 값이 표시된 기존 역할 테이블이 나타납니다.

  9. 새 역할 이름 텍스트 상자에서 manager를 employee로 바꾼 다음 역할 추가를 클릭합니다.

    기존 역할 테이블에 새 값이 표시됩니다.

  10. 다음을 클릭합니다.

    새 사용자 추가 단계가 표시됩니다.

  11. 사용자 만들기 폼에서 다음 값을 지정합니다.

    사용자 이름

    manager

    암호

    manager!

    암호 확인

    manager!

    전자 메일

    manager@contoso.com

    보안 질문

    manager

    보안 대답

    manager

  12. 사용자 만들기를 클릭합니다.

    성공 메시지가 표시됩니다.

    참고

    전자 메일, 보안 질문보안 대답 값은 폼에서 필수 사항이지만 이 예제에서는 사용되지 않습니다.

  13. 계속을 클릭합니다.

    사용자 만들기 폼이 다시 표시됩니다.

  14. 사용자 만들기 폼에서 다음 값을 지정합니다.

    사용자 이름

    employee

    암호

    employee!

    암호 확인

    employee!

    전자 메일

    employee@contoso.com

    보안 질문

    Employee

    보안 대답

    employee

  15. 사용자 만들기를 클릭합니다.

    성공 메시지가 표시됩니다.

  16. 마침을 클릭합니다.

    웹 사이트 관리 도구가 다시 나타납니다.

  17. 사용자 관리를 클릭합니다.

    사용자 목록이 표시됩니다.

  18. employee 사용자에 대해 역할 편집을 클릭한 다음 employee 역할을 선택합니다.

  19. manager 사용자에 대해 역할 편집을 클릭한 다음 manager 역할을 선택합니다.

  20. 웹 사이트 관리 도구를 호스팅하는 브라우저 창을 닫습니다.

  21. 수정된 Web.config 파일을 다시 로드할지 묻는 메시지 상자가 나타나면 를 클릭합니다.

이렇게 하면 웹 서비스 설치가 완료됩니다. 이때 F5 키를 눌러 클라이언트 응용 프로그램을 실행할 수 있으며, 그러면 ASP.NET Development Server가 클라이언트 응용 프로그램과 함께 자동으로 시작됩니다. 응용 프로그램을 종료한 후에도 서버는 계속 실행되지만 응용 프로그램을 다시 시작하면 서버도 다시 시작됩니다. 이를 통해 Web.config에 대해 수행한 변경 사항을 탐지할 수 있습니다.

서버를 수동으로 중지하려면 작업 표시줄의 알림 영역에서 ASP.NET Development Server 아이콘을 마우스 오른쪽 단추로 클릭한 다음 중지를 클릭합니다. 이는 정상적인 방법으로 다시 시작하는 경우에 유용할 수도 있습니다.

폼 인증 추가

다음 절차에서는 사용자에 대한 유효성 검사를 시도하고 사용자가 유효하지 않은 자격 증명을 제공하면 액세스를 거부하는 코드를 기본 폼에 추가합니다. 이를 위해 하드 코드된 사용자 이름과 암호를 사용하여 서비스를 테스트합니다.

응용 프로그램 코드에서 사용자의 유효성을 검사하려면

  1. 솔루션 탐색기의 ClientAppServicesDemo 프로젝트에서 System.Web 어셈블리에 대한 참조를 추가합니다.

  2. Form1 파일을 선택한 다음 Visual Studio 주 메뉴에서 보기 | 코드를 선택합니다.

  3. 코드 편집기에서 Form1 파일의 맨 위에 다음 문을 추가합니다.

    Imports System.Net
    Imports System.Threading
    Imports System.Web.ClientServices
    Imports System.Web.ClientServices.Providers
    Imports System.Web.Security
    
    using System.Net;
    using System.Threading;
    using System.Web.ClientServices;
    using System.Web.ClientServices.Providers;
    using System.Web.Security;
    
  4. 솔루션 탐색기에서 Form1을 두 번 클릭하여 디자이너를 표시합니다.

  5. 디자이너에서 폼 화면을 두 번 클릭하여 Form1_Load라는 Form.Load 이벤트 처리기를 생성합니다.

    커서가 Form1_Load 메서드에 있는 상태로 코드 편집기가 나타납니다.

  6. Form1_Load 메서드에 다음 코드를 추가합니다.

    이 코드에서는 응용 프로그램을 종료하여 인증되지 않은 사용자에 대한 액세스를 거부합니다. 또한 폼에 대한 인증되지 않은 사용자의 액세스는 허용하고 특정 기능에 대한 액세스를 거부할 수도 있습니다. 일반적으로는 사용자 이름과 암호를 이와 같이 하드 코딩하지 않지만 테스트 시에는 유용합니다. 다음 단원에서는 이 코드를 로그인 대화 상자를 표시하고 예외 처리를 포함하는 보다 견고한 코드로 바꿉니다.

    static Membership.ValidateUser 메서드는 .NET Framework 버전 2.0에 있습니다. 이 메서드는 해당 작업을 구성된 인증 공급자에 위임하여 인증에 성공할 경우 true를 반환합니다. 응용 프로그램에는 클라이언트 인증 공급자에 대한 직접 참조가 필요하지 않습니다.

    If Not Membership.ValidateUser("manager", "manager!") Then
    
        MessageBox.Show("Unable to authenticate.", "Not logged in", _
            MessageBoxButtons.OK, MessageBoxIcon.Error)
        Application.Exit()
    
    End If
    
    if (!Membership.ValidateUser("manager", "manager!"))
    {
        MessageBox.Show("Unable to authenticate.", "Not logged in",
            MessageBoxButtons.OK, MessageBoxIcon.Error);
        Application.Exit();
    }
    

이제 F5 키를 눌러 응용 프로그램을 실행할 수 있으며 올바른 사용자 이름과 암호를 제공하기 때문에 폼을 확인할 수 있습니다.

참고

응용 프로그램을 실행할 수 없으면 ASP.NET Development Server를 중지해 봅니다. 그런 다음 서버가 다시 시작되면 포트가 55555로 설정되어 있는지 확인합니다.

대신 오류 메시지가 표시되도록 하려면 ValidateUser 매개 변수를 변경합니다. 예를 들어 두 번째 "manager!" 매개 변수를 "MANAGER" 같은 잘못된 암호로 바꿉니다.

로그인 폼을 자격 증명 공급자로 추가

응용 프로그램 코드에서 사용자 자격 증명을 가져와 ValidateUser 메서드에 전달할 수 있습니다. 그러나 일반적으로 나중에 변경하려는 경우에 대비해 자격 증명을 가져오는 코드를 응용 프로그램 코드와 구분해 두는 것이 좋습니다.

다음 절차에서는 응용 프로그램에서 자격 증명 공급자를 사용하도록 구성한 다음 ValidateUser 메서드 호출을 변경하여 두 매개 변수 모두에 대해 Empty를 전달합니다. 빈 문자열은 구성된 자격 증명 공급자의 GetCredentials 메서드를 호출하도록 ValidateUser 메서드에 알립니다.

응용 프로그램에서 자격 증명 공급자를 사용하도록 구성하려면

  1. 솔루션 탐색기에서 ClientAppServicesDemo 프로젝트를 선택하고 프로젝트 메뉴에서 ClientAppServicesDemo 속성을 클릭합니다.

    프로젝트 디자이너가 나타납니다.

  2. 서비스 탭에서 옵션: 자격 증명 공급자를 다음 값으로 설정합니다. 이 값은 어셈블리로 한정된 형식 이름을 나타냅니다.

    ClientAppServicesDemo.Login, ClientAppServicesDemo
    
  3. Form1 코드 파일에서 Form1_Load 메서드의 코드를 다음 코드로 바꿉니다.

    이 코드는 시작 메시지를 표시한 후 다음 단계에서 추가할 ValidateUsingCredentialsProvider 메서드를 호출합니다. 사용자가 인증되지 않은 경우 ValidateUsingCredentialsProvider 메서드가 false를 반환하고 Form1_Load 메서드가 반환됩니다. 이를 통해 응용 프로그램이 종료되기 전까지 추가 코드가 실행되지 않습니다. 시작 메시지는 응용 프로그램이 다시 시작되는 시기를 명시적으로 지정하는 데 유용합니다. 응용 프로그램을 다시 시작하는 코드는 이 연습의 뒷부분에서 로그아웃을 구현할 때 추가합니다.

    MessageBox.Show("Welcome to the Client Application Services Demo.", _
        "Welcome!")
    
    If Not ValidateUsingCredentialsProvider() Then Return
    
    MessageBox.Show("Welcome to the Client Application Services Demo.",
        "Welcome!");
    
    if (!ValidateUsingCredentialsProvider()) return;
    
  4. Form1_Load 메서드 뒤에 다음 메서드를 추가합니다.

    이 메서드는 static Membership.ValidateUser 메서드에 빈 문자열을 전달하여 로그인 대화 상자가 나타나도록 합니다. 인증 서비스를 사용할 수 없는 경우 ValidateUser 메서드는 WebException을 throw합니다. 이 경우 ValidateUsingCredentialsProvider 메서드는 사용자가 다시 오프라인 모드로 시도하려는 경우 경고 메시지를 표시합니다. 이 기능을 사용하려면 방법: 클라이언트 응용 프로그램 서비스 구성에 설명된 오프라인으로 로그인할 수 있도록 로컬에 암호 해시 저장 기능이 필요합니다. 이 기능은 새 프로젝트에서 기본값으로 사용됩니다.

    사용자의 유효성을 검사하지 않으면 ValidateUsingCredentialsProvider 메서드에서 오류 메시지를 표시하고 응용 프로그램을 종료합니다. 마지막으로 이 메서드는 인증 시도의 결과를 반환합니다.

    Private Function ValidateUsingCredentialsProvider() As Boolean
    
        Dim isAuthorized As Boolean = False
    
        Try
    
            ' Call ValidateUser with empty strings in order to display the 
            ' login dialog box configured as a credentials provider.
            isAuthorized = Membership.ValidateUser( _
                String.Empty, String.Empty)
    
        Catch ex As System.Net.WebException
    
            If DialogResult.OK = MessageBox.Show( _
                "Unable to access the authentication service." & _
                Environment.NewLine & "Attempt login in offline mode?", _
                "Warning", MessageBoxButtons.OKCancel, _
                MessageBoxIcon.Warning) Then
    
                ConnectivityStatus.IsOffline = True
                isAuthorized = Membership.ValidateUser( _
                    String.Empty, String.Empty)
    
            End If
    
        End Try
    
        If Not isAuthorized Then
    
            MessageBox.Show("Unable to authenticate.", "Not logged in", _
                MessageBoxButtons.OK, MessageBoxIcon.Error)
            Application.Exit()
    
        End If
    
        Return isAuthorized
    
    End Function
    
    private bool ValidateUsingCredentialsProvider()
    {
        bool isAuthorized = false;
        try
        {
            // Call ValidateUser with empty strings in order to display the 
            // login dialog box configured as a credentials provider.
            isAuthorized = Membership.ValidateUser(
                String.Empty, String.Empty);
        }
        catch (System.Net.WebException)
        {
            if (DialogResult.OK == MessageBox.Show(
                "Unable to access the authentication service." +
                Environment.NewLine + "Attempt login in offline mode?",
                "Warning", MessageBoxButtons.OKCancel, 
                MessageBoxIcon.Warning))
            {
                ConnectivityStatus.IsOffline = true;
                isAuthorized = Membership.ValidateUser(
                    String.Empty, String.Empty);
            }
        }
    
        if (!isAuthorized)
        {
            MessageBox.Show("Unable to authenticate.", "Not logged in",
                MessageBoxButtons.OK, MessageBoxIcon.Error);
            Application.Exit();
        }
        return isAuthorized;
    }
    

로그인 폼 만들기

자격 증명 공급자는 IClientFormsAuthenticationCredentialsProvider 인터페이스를 구현하는 클래스입니다. 이 인터페이스에는 ClientFormsAuthenticationCredentials 개체를 반환하는 GetCredentials라는 단일 메서드가 들어 있습니다. 다음 절차에서는 GetCredentials를 구현하여 해당 메서드를 표시하고 사용자가 지정한 자격 증명을 반환하는 로그인 대화 상자를 만드는 방법에 대해 설명합니다.

Visual Basic에서는 로그인 폼 템플릿을 제공하기 때문에 Visual Basic 및 C#에 대해 개별적인 절차가 제공되며 이를 통해 시간과 코딩 작업량을 절감할 수 있습니다.

Visual Basic에서 로그인 대화 상자를 자격 증명 공급자로 만들려면

  1. 솔루션 탐색기에서 ClientAppServicesDemo 프로젝트를 선택하고 프로젝트 메뉴에서 새 항목 추가를 선택합니다.

  2. 새 항목 추가 대화 상자에서 로그인 폼 템플릿을 선택하고 항목 이름을 Login.vb로 변경한 다음 추가를 클릭합니다.

    Windows Forms 디자이너에서 로그인 대화 상자가 나타납니다.

  3. 디자이너에서 확인 단추를 선택한 다음 속성 창에서 DialogResult를 OK로 설정합니다.

  4. 디자이너에서 CheckBox 컨트롤을 암호 텍스트 상자 아래의 폼에 추가합니다.

  5. 속성 창에서 rememberMeCheckBox의 (이름) 값과 &Remember me의 텍스트 값을 지정합니다.

  6. Visual Studio 주 메뉴에서 보기 | 코드를 선택합니다.

  7. 코드 편집기에서 파일의 맨 위에 다음 코드를 추가합니다.

    Imports System.Web.ClientServices.Providers
    
  8. 클래스에서 IClientFormsAuthenticationCredentialsProvider 인터페이스를 구현하도록 클래스 시그니처를 수정합니다.

    Public Class Login
        Implements IClientFormsAuthenticationCredentialsProvider
    
  9. 커서가 IClientformsAuthenticationCredentialsProvider 뒤에 오도록 한 다음 Enter 키를 눌러 GetCredentials 메서드를 생성합니다.

  10. GetCredentials 구현을 찾아 다음 코드로 바꿉니다.

    Public Function GetCredentials() As  _
        ClientFormsAuthenticationCredentials Implements _
        IClientFormsAuthenticationCredentialsProvider.GetCredentials
    
        If Me.ShowDialog() = DialogResult.OK Then
            Return New ClientFormsAuthenticationCredentials( _
                UsernameTextBox.Text, PasswordTextBox.Text, _
                rememberMeCheckBox.Checked)
        Else
            Return Nothing
        End If
    
    End Function
    

다음 C# 절차에서는 간단한 로그인 대화 상자의 전체 코드 목록을 제공합니다. 이 대화 상자의 레이아웃은 다소 조잡하지만 중요한 부분은 GetCredentials 구현입니다.

C#에서 로그인 대화 상자를 자격 증명 공급자로 만들려면

  1. 솔루션 탐색기에서 ClientAppServicesDemo 프로젝트를 선택한 다음 프로젝트 메뉴에서 클래스 추가를 선택합니다.

  2. 새 항목 추가 대화 상자에서 이름을 Login.cs로 바꾼 다음 추가를 클릭합니다.

    코드 편집기에서 Login.cs 파일이 열립니다.

  3. 기본 코드를 다음 코드로 바꿉니다.

    using System.Windows.Forms;
    using System.Web.ClientServices.Providers;
    
    namespace ClientAppServicesDemo
    {
        class Login : Form,
            IClientFormsAuthenticationCredentialsProvider
        {
            private TextBox usernameTextBox;
            private TextBox passwordTextBox;
            private CheckBox rememberMeCheckBox;
            private Button OK;
            private Button cancel;
            private Label label1;
            private Label label2;
    
            public ClientFormsAuthenticationCredentials GetCredentials()
            {
                if (this.ShowDialog() == DialogResult.OK)
                {
                    return new ClientFormsAuthenticationCredentials(
                        usernameTextBox.Text, passwordTextBox.Text,
                        rememberMeCheckBox.Checked);
                }
                else
                {
                    return null;
                }
            }
    
            public Login()
            {
                InitializeComponent();
            }
    
            private void CloseForm(object sender, System.EventArgs e)
            {
                this.Close();
            }
    
            private void InitializeComponent()
            {
                this.label1 = new System.Windows.Forms.Label();
                this.usernameTextBox = new System.Windows.Forms.TextBox();
                this.label2 = new System.Windows.Forms.Label();
                this.passwordTextBox = new System.Windows.Forms.TextBox();
                this.rememberMeCheckBox = new System.Windows.Forms.CheckBox();
                this.OK = new System.Windows.Forms.Button();
                this.cancel = new System.Windows.Forms.Button();
                this.SuspendLayout();
                // 
                // label1
                // 
                this.label1.AutoSize = true;
                this.label1.Location = new System.Drawing.Point(13, 13);
                this.label1.Name = "label1";
                this.label1.Size = new System.Drawing.Size(58, 13);
                this.label1.TabIndex = 0;
                this.label1.Text = "&User name";
                // 
                // usernameTextBox
                // 
                this.usernameTextBox.Location = new System.Drawing.Point(13, 30);
                this.usernameTextBox.Name = "usernameTextBox";
                this.usernameTextBox.Size = new System.Drawing.Size(157, 20);
                this.usernameTextBox.TabIndex = 1;
                // 
                // label2
                // 
                this.label2.AutoSize = true;
                this.label2.Location = new System.Drawing.Point(13, 57);
                this.label2.Name = "label2";
                this.label2.Size = new System.Drawing.Size(53, 13);
                this.label2.TabIndex = 2;
                this.label2.Text = "&Password";
                // 
                // passwordTextBox
                // 
                this.passwordTextBox.Location = new System.Drawing.Point(13, 74);
                this.passwordTextBox.Name = "passwordTextBox";
                this.passwordTextBox.PasswordChar = '*';
                this.passwordTextBox.Size = new System.Drawing.Size(157, 20);
                this.passwordTextBox.TabIndex = 3;
                // 
                // rememberMeCheckBox
                // 
                this.rememberMeCheckBox.AutoSize = true;
                this.rememberMeCheckBox.Location = new System.Drawing.Point(13, 101);
                this.rememberMeCheckBox.Name = "rememberMeCheckBox";
                this.rememberMeCheckBox.Size = new System.Drawing.Size(94, 17);
                this.rememberMeCheckBox.TabIndex = 4;
                this.rememberMeCheckBox.Text = "&Remember me";
                this.rememberMeCheckBox.UseVisualStyleBackColor = true;
                // 
                // OK
                // 
                this.OK.DialogResult = System.Windows.Forms.DialogResult.OK;
                this.OK.Location = new System.Drawing.Point(13, 125);
                this.OK.Name = "OK";
                this.OK.Size = new System.Drawing.Size(75, 23);
                this.OK.TabIndex = 5;
                this.OK.Text = "&OK";
                this.OK.UseVisualStyleBackColor = true;
                // 
                // cancel
                // 
                this.cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
                this.cancel.Location = new System.Drawing.Point(95, 125);
                this.cancel.Name = "cancel";
                this.cancel.Size = new System.Drawing.Size(75, 23);
                this.cancel.TabIndex = 6;
                this.cancel.Text = "&Cancel";
                this.cancel.UseVisualStyleBackColor = true;
                // 
                // Login
                // 
                this.AcceptButton = this.OK;
                this.CancelButton = this.cancel;
                this.ClientSize = new System.Drawing.Size(187, 168);
                this.Controls.Add(this.cancel);
                this.Controls.Add(this.OK);
                this.Controls.Add(this.rememberMeCheckBox);
                this.Controls.Add(this.passwordTextBox);
                this.Controls.Add(this.label2);
                this.Controls.Add(this.usernameTextBox);
                this.Controls.Add(this.label1);
                this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
                this.MaximizeBox = false;
                this.MinimizeBox = false;
                this.Name = "Login";
                this.Text = "Login";
                this.ResumeLayout(false);
                this.PerformLayout();
    
            }
        }
    
    }
    

이제 응용 프로그램을 실행하여 대화 상자가 나타나는지 확인할 수 있습니다. 이 코드를 테스트하려면 유요한 자격 증명과 유효하지 않은 자격 증명을 모두 시도하여 유요한 자격 증명으로만 폼에 액세스할 수 있음을 확인해 봅니다. 유효한 사용자 이름은 암호가 각각 employee! 및 manager!인 employee 및 manager입니다.

참고

여기서 암호 저장을 선택해서는 안 되며, 그렇지 않으면 이 연습의 뒷부분에서 로그아웃을 구현할 때까지 다른 사용자로 로그인할 수 없게 됩니다.

역할 기반 기능 추가

다음 절차에서는 폼에 단추를 추가하여 관리자 역할의 사용자에게만 표시합니다.

사용자 역할을 기반으로 사용자 인터페이스를 변경하려면

  1. 솔루션 탐색기의 ClientAppServicesDemo 프로젝트에서 Form1을 선택한 다음 Visual Studio 주 메뉴에서 보기 | 디자이너를 선택합니다.

  2. 디자이너의 도구 상자에서 Button 컨트롤을 폼에 추가합니다.

  3. 속성 창에서 단추에 대해 다음 속성을 설정합니다.

    Property

    (이름)

    managerOnlyButton

    Text

    &Manager task

    Visible

    False

  4. Form1에 대한 코드 편집기에서 Form1_Load 메서드의 끝에 다음 코드를 추가합니다.

    이 코드는 다음 단계에서 추가할 DisplayButtonForManagerRole 메서드를 호출합니다.

    DisplayButtonForManagerRole()
    
    DisplayButtonForManagerRole();
    
  5. 다음 메서드를 Form1 클래스의 끝에 추가합니다.

    이 메서드는 static Thread.CurrentPrincipal 속성에서 반환하는 IPrincipalIsInRole 메서드를 호출합니다. 클라이언트 응용 프로그램 서비스를 사용하도록 구성된 응용 프로그램의 경우에는 이 속성이 ClientRolePrincipal을 반환합니다. 이 클래스는 IPrincipal 인터페이스를 구현하므로 이를 명시적으로 참조할 필요는 없습니다.

    사용자가 "관리자" 역할에 있는 경우 DisplayButtonForManagerRole 메서드는 managerOnlyButton의 Visible 속성을 true로 설정합니다. 또한 이 메서드는 역할 서비스를 사용할 수 없음을 나타내는 WebException이 throw되는 경우 오류 메시지를 표시합니다.

    참고

    사용자 로그인이 만료되는 경우 IsInRole 메서드는 항상 false를 반환합니다. 하지만 이 연습의 예제 코드에서처럼 응용 프로그램에서 IsInRole 메서드를 인증 직후 한 번 호출하는 경우에는 예외입니다. 응용 프로그램에서 다른 때 사용자 역할을 검색해야 하는 경우에는 로그인이 만료된 사용자에 대해 유효성을 검사하는 코드를 추가해야 할 수 있습니다. 역할에 유효한 모든 사용자가 할당되면 ClientRoleProvider.GetRolesForUser 메서드를 호출하여 로그인이 만료되었는지 여부를 확인할 수 있습니다. 역할이 반환되지 않으면 로그인이 만료된 것입니다. 이 기능의 예제를 보려면 GetRolesForUser 메서드를 참조하십시오. 이 기능은 응용 프로그램 구성에서 서버 쿠키가 만료될 때마다 다시 사용자 로그온을 선택한 경우에만 필요합니다. 자세한 내용은 방법: 클라이언트 응용 프로그램 서비스 구성을 참조하십시오.

    Private Sub DisplayButtonForManagerRole()
    
        Try
    
            If Thread.CurrentPrincipal.IsInRole("manager") Then
    
                managerOnlyButton.Visible = True
    
            End If
    
        Catch ex As System.Net.WebException
    
            MessageBox.Show("Unable to access the roles service.", _
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
    
        End Try
    
    End Sub
    
    private void DisplayButtonForManagerRole()
    {
        try
        {
            if (Thread.CurrentPrincipal.IsInRole("manager"))
            {
                managerOnlyButton.Visible = true;
            }
        }
        catch (System.Net.WebException)
        {
            MessageBox.Show("Unable to access the role service.",
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
    

인증에 성공하면 클라이언트 인증 공급자가 Thread.CurrentPrincipal 속성을 ClientRolePrincipal 클래스의 인스턴스로 설정합니다. 이 클래스는 작업이 구성된 역할 공급자에 위임되도록 IsInRole 메서드를 구현합니다. 이전과 마찬가지로 응용 프로그램 코드에는 서비스 공급자에 대한 직접 참조가 필요하지 않습니다.

이제 응용 프로그램을 실행하고 직원으로 로그인하여 단추가 표시되지 않음을 확인한 다음 관리자로 로그인하여 단추를 확인할 수 있습니다.

웹 설정 액세스

다음 절차에서는 폼에 텍스트 상자를 추가하여 웹 설정에 바인딩합니다. 인증 및 역할을 사용하는 이전 코드와 마찬가지로 설정 코드는 설정 공급자에 직접 액세스하는 대신 Visual Studio에서 프로젝트에 대해 생성된 Settings 클래스(C#에서는 Properties.Settings.Default, Visual Basic에서는 My.Settings로 각각 액세스).

사용자 인터페이스에서 웹 설정을 사용하려면

  1. 작업 표시줄의 알림 영역을 확인하여 ASP.NET Web Development Server가 계속 실행 중인지 확인합니다. 서버를 중지한 경우 응용 프로그램을 다시 시작(서버가 자동으로 시작됨)한 다음 로그인 대화 상자를 닫습니다.

  2. 솔루션 탐색기에서 ClientAppServicesDemo 프로젝트를 선택하고 프로젝트 메뉴에서 ClientAppServicesDemo 속성을 클릭합니다.

    프로젝트 디자이너가 나타납니다.

  3. 설정 탭에서 웹 설정 로드를 클릭합니다.

    로그인 대화 상자가 나타납니다.

  4. 직원 또는 관리자에 해당하는 자격 증명을 입력하고 로그인을 클릭합니다. 사용할 웹 설정은 인증된 사용자만 액세스할 수 있도록 구성되므로 로그인 건너뛰기를 클릭하면 아무런 설정도 로드되지 않습니다.

    디자이너에서 기본값이 DefaultText로 지정된 WebSettingsTestText 설정이 나타납니다. 또한 프로젝트에 대해 WebSettingsTestText 속성이 들어 있는 Settings 클래스가 생성됩니다.

  5. 솔루션 탐색기의 ClientAppServicesDemo 프로젝트에서 Form1을 선택한 다음 Visual Studio 주 메뉴에서 보기 | 디자이너를 선택합니다.

  6. 디자이너에서 TextBox 컨트롤을 폼에 추가합니다.

  7. 속성 창에서 webSettingsTestTextBox의 (이름) 값을 지정합니다.

  8. 코드 편집기에서 Form1_Load 메서드의 끝에 다음 코드를 추가합니다.

    이 코드는 다음 단계에서 추가할 BindWebSettingsTestTextBox 메서드를 호출합니다.

    BindWebSettingsTestTextBox()
    
    BindWebSettingsTestTextBox();
    
  9. 다음 메서드를 Form1 클래스의 끝에 추가합니다.

    이 메서드는 webSettingsTestTextBox의 Text 속성을 이 절차의 앞부분에서 생성한 Settings 클래스의 WebSettingsTestText 속성에 바인딩합니다. 또한 이 메서드는 웹 설정 서비스를 사용할 수 없음을 나타내는 WebException이 throw되는 경우 오류 메시지를 표시합니다.

    Private Sub BindWebSettingsTestTextBox()
    
        Try
    
            Me.webSettingsTestTextBox.DataBindings.Add("Text", _
                My.Settings, "WebSettingsTestText")
    
        Catch ex As WebException
    
            MessageBox.Show("Unable to access the Web settings service.", _
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
    
        End Try
    
    End Sub
    
    private void BindWebSettingsTestTextBox()
    {
        try
        {
            this.webSettingsTestTextBox.DataBindings.Add("Text",
                Properties.Settings.Default, "WebSettingsTestText");
        }
        catch (WebException)
        {
            MessageBox.Show("Unable to access the Web settings service.",
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
    

    참고

    일반적으로는 데이터 바인딩을 사용하여 컨트롤과 웹 설정 간의 자동 양방향 통신을 활성화합니다. 하지만 다음 예제에서처럼 웹 설정에 직접 액세스할 수도 있습니다.

    webSettingsTestTextBox.Text = My.Settings.WebSettingsTestText
    
    webSettingsTestTextBox.Text =
        Properties.Settings.Default.WebSettingsTestText;
    
  10. 디자이너에서 폼을 선택한 다음 속성 창에서 이벤트 단추를 클릭합니다.

  11. FormClosing 이벤트를 선택한 다음 Enter 키를 눌러 이벤트 처리기를 생성합니다.

  12. 생성된 메서드를 다음 코드로 바꿉니다.

    FormClosing 이벤트 처리기에서 SaveSettings 메서드를 호출합니다. 이 메서드는 다음 단원에서 추가할 로그아웃 기능에도 사용됩니다. SaveSettings 메서드는 먼저 사용자가 로그아웃하지 않았는지 확인합니다. 이를 위해 현재 주체에서 반환하는 IIdentityAuthenticationType 속성을 확인합니다. 현재 주체는 static CurrentPrincipal 속성을 통해 검색됩니다. 사용자가 클라이언트 응용 프로그램 서비스에 대해 인증된 경우 인증 형식은 "ClientForms"가 됩니다. 사용자가 로그아웃한 후 유효한 Windows ID를 가질 수도 있으므로 SaveSettings 메서드는 IIdentity.IsAuthenticated 속성을 확인할 수 없습니다.

    사용자가 로그아웃하지 않은 경우에는 SaveSettings 메서드가 이 절차의 앞부분에서 생성한 Settings 클래스의 Save 메서드를 호출합니다. 인증 쿠키가 만료되면 이 메서드에서 WebException을 throw할 수 있습니다. 이는 응용 프로그램 구성에서 서버 쿠키가 만료될 때마다 다시 사용자 로그온을 선택한 경우에만 발생합니다. 자세한 내용은 방법: 클라이언트 응용 프로그램 서비스 구성을 참조하십시오. SaveSettings 메서드는 ValidateUser를 호출하여 로그인 대화 상자를 표시함으로써 쿠키 만료를 처리합니다. 사용자가 로그인에 성공하면 SaveSettings 메서드는 자신을 호출하여 설정을 다시 저장하려고 합니다.

    이전 코드에서와 마찬가지로 원격 서비스를 사용할 수 없으면 SaveSettings 메서드는 오류 메시지를 표시합니다. 설정 공급자가 원격 서비스에 액세스할 수 없으면 설정은 로컬 캐시에 계속 저장되며 응용 프로그램이 다시 시작되면 해당 설정도 다시 로드됩니다.

    Private Sub Form1_FormClosing(ByVal sender As Object, _
        ByVal e As FormClosingEventArgs) Handles Me.FormClosing
    
        SaveSettings()
    
    End Sub
    
    Private Sub SaveSettings()
    
        ' Return without saving if the authentication type is not
        ' "ClientForms". This indicates that the user is logged out.
        If Not Thread.CurrentPrincipal.Identity.AuthenticationType _
            .Equals("ClientForms") Then Return
    
        Try
    
            My.Settings.Save()
    
        Catch ex As WebException
    
            If ex.Message.Contains("You must log on to call this method.") Then
    
                MessageBox.Show( _
                    "Your login has expired. Please log in again to save " & _
                    "your settings.", "Attempting to save settings...")
    
                Dim isAuthorized As Boolean = False
    
                Try
    
                    ' Call ValidateUser with empty strings in order to 
                    ' display the login dialog box configured as a 
                    ' credentials provider.
                    If Not Membership.ValidateUser( _
                        String.Empty, String.Empty) Then
    
                        MessageBox.Show("Unable to authenticate. " & _
                            "Settings were not saved on the remote service.", _
                            "Not logged in", MessageBoxButtons.OK, _
                            MessageBoxIcon.Error)
    
                    Else
    
                        ' Try again.
                        SaveSettings()
    
                    End If
    
                Catch ex2 As System.Net.WebException
    
                    MessageBox.Show( _
                        "Unable to access the authentication service. " & _
                        "Settings were not saved on the remote service.", _
                        "Not logged in", MessageBoxButtons.OK, _
                        MessageBoxIcon.Warning)
    
                End Try
    
            Else
    
                MessageBox.Show("Unable to access the Web settings service. " & _
                    "Settings were not saved on the remote service.", _
                    "Not logged in", MessageBoxButtons.OK, _
                    MessageBoxIcon.Warning)
    
            End If
    
        End Try
    
    End Sub
    
    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        SaveSettings();
    }
    
    private void SaveSettings()
    {
        // Return without saving if the authentication type is not
        // "ClientForms". This indicates that the user is logged out.
        if (!Thread.CurrentPrincipal.Identity.AuthenticationType
          .Equals("ClientForms")) return;
    
        try
        {
            Properties.Settings.Default.Save();
        }
        catch (WebException ex)
        {
            if (ex.Message.Contains("You must log on to call this method."))
            {
                MessageBox.Show(
                    "Your login has expired. Please log in again to save " +
                    "your settings.", "Attempting to save settings...");
    
                try
                {
                    // Call ValidateUser with empty strings in order to 
                    // display the login dialog box configured as a 
                    // credentials provider.
                    if (!Membership.ValidateUser(String.Empty, String.Empty))
                    {
                        MessageBox.Show("Unable to authenticate. " +
                            "Settings were not saved on the remote service.",
                            "Not logged in", MessageBoxButtons.OK, 
                            MessageBoxIcon.Error);
                    }
                    else
                    {
                        // Try again.
                        SaveSettings();
                    }
                }
                catch (System.Net.WebException)
                {
                    MessageBox.Show(
                        "Unable to access the authentication service. " +
                        "Settings were not saved on the remote service.",
                        "Not logged in", MessageBoxButtons.OK, 
                        MessageBoxIcon.Warning);
                }
            }
            else
            {
                MessageBox.Show("Unable to access the Web settings service. " +
                    "Settings were not saved on the remote service.", 
                    "Not logged in", MessageBoxButtons.OK, 
                    MessageBoxIcon.Warning);
            }
        }
    }
    
  13. 다음 메서드를 Form1 클래스의 끝에 추가합니다.

    이 코드는 ClientSettingsProvider.SettingsSaved 이벤트를 처리하고 설정을 저장할 수 없는 경우에는 경고를 표시합니다. 설정 서비스를 사용할 수 없거나 인증 쿠키가 만료된 경우에는 SettingsSaved 이벤트가 발생하지 않습니다. SettingsSaved 이벤트가 발생하는 경우의 한 가지 예는 사용자가 이미 로그아웃한 경우입니다. 이 이벤트 처리기를 테스트하려면 Save 메서드 호출 바로 앞에 있는 SaveSettings 메서드에 로그아웃 코드를 추가합니다. 사용할 수 있는 로그아웃 코드는 다음 단원에 설명되어 있습니다.

    Private WithEvents settingsProvider As ClientSettingsProvider = My.Settings _
        .Providers("System.Web.ClientServices.Providers.ClientSettingsProvider")
    
    Private Sub Form1_SettingsSaved(ByVal sender As Object, _
        ByVal e As SettingsSavedEventArgs) _
        Handles settingsProvider.SettingsSaved
    
        ' If any settings were not saved, display a list of them.
        If e.FailedSettingsList.Count > 0 Then
    
            Dim failedSettings As String = String.Join( _
                Environment.NewLine, e.FailedSettingsList.ToArray())
    
            Dim message As String = String.Format("{0}{1}{1}{2}", _
                "The following setting(s) were not saved:", _
                Environment.NewLine, failedSettings)
    
            MessageBox.Show(message, "Unable to save settings", _
                MessageBoxButtons.OK, MessageBoxIcon.Warning)
    
        End If
    
    End Sub
    
    private void Form1_SettingsSaved(object sender,
        SettingsSavedEventArgs e)
    {
        // If any settings were not saved, display a list of them.
        if (e.FailedSettingsList.Count > 0)
        {
            String failedSettings = String.Join(
                Environment.NewLine,
                e.FailedSettingsList.ToArray());
    
            String message = String.Format("{0}{1}{1}{2}",
                "The following setting(s) were not saved:",
                Environment.NewLine, failedSettings);
    
            MessageBox.Show(message, "Unable to save settings",
                MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
    
  14. C#의 경우 다음 코드를 Form1_Load 메서드의 끝에 추가합니다. 이 코드는 마지막 단계에서 추가한 메서드를 SettingsSaved 이벤트와 연결합니다.

    ((ClientSettingsProvider)Properties.Settings.Default.Providers
        ["System.Web.ClientServices.Providers.ClientSettingsProvider"])
        .SettingsSaved += 
        new EventHandler<SettingsSavedEventArgs>(Form1_SettingsSaved);
    

이때 응용 프로그램을 테스트하려면 해당 응용 프로그램을 직원 및 관리자로 여러 번 실행한 다음 텍스트 상자에 서로 다른 값을 입력합니다. 값은 사용자 단위로 세션에서 계속 유지됩니다.

로그아웃 구현

사용자가 로그인할 때 암호 저장 확인란을 선택하면 응용 프로그램에서는 다음 번에 실행될 때 해당 사용자를 자동으로 인증합니다. 그러면 응용 프로그램이 오프라인 모드에 있는 동안이나 인증 쿠키가 만료될 때까지 자동 인증이 계속 진행됩니다. 그러나 경우에 따라 응용 프로그램에 여러 사용자가 액세스해야 하거나, 한 명의 사용자가 이따금 다른 자격 증명으로 로그인하는 상황이 발생할 수도 있습니다. 이 시나리오를 사용하려면 다음 절차에 설명된 것처럼 로그아웃 기능을 구현해야 합니다.

로그아웃 기능을 구현하려면

  1. Form1 디자이너의 도구 상자에서 Button 컨트롤을 폼에 추가합니다.

  2. 속성 창에서 logoutButton의 (이름) 값과 &Log Out의 텍스트 값을 지정합니다.

  3. logoutButton을 두 번 클릭하여 Click 이벤트 처리기를 생성합니다.

    커서가 logoutButton_Click 메서드에 있는 상태로 코드 편집기가 나타납니다.

  4. 생성된 logoutButton_Click 메서드를 다음 코드로 바꿉니다.

    이 이벤트 처리기는 먼저 이전 단원에서 추가한 SaveSettings 메서드를 호출합니다. 그런 다음 ClientFormsAuthenticationMembershipProvider.Logout 메서드를 호출합니다. 인증 서비스를 사용할 수 없는 경우 Logout 메서드는 WebException을 throw합니다. 이 경우 logoutButton_Click 메서드는 경고 메시지를 표시하고 일시적으로 오프라인 모드로 전환하여 사용자를 로그아웃시킵니다. 오프라인 모드에 대해서는 다음 단원에서 설명합니다.

    로그아웃은 응용 프로그램이 다시 시작될 때 로그인이 필요하도록 로컬 인증 쿠키를 삭제합니다. 로그아웃한 후에는 이벤트 처리기가 응용 프로그램을 다시 시작합니다. 응용 프로그램이 다시 시작되면 시작 메시지가 나타난 다음 로그인 대화 상자가 표시됩니다. 시작 메시지는 응용 프로그램이 다시 시작되었음을 분명하게 알려 주는 역할을 합니다. 이를 통해 사용자가 설정을 저장하기 위해 로그인해야 하는 상황에서 응용 프로그램이 다시 시작되었기 때문에 다시 로그인해야 한다는 혼동을 막을 수 있습니다.

    Private Sub logoutButton_Click(ByVal sender As Object, _
        ByVal e As EventArgs) Handles logoutButton.Click
    
        SaveSettings()
    
        Dim authProvider As ClientFormsAuthenticationMembershipProvider = _
            CType(System.Web.Security.Membership.Provider,  _
            ClientFormsAuthenticationMembershipProvider)
    
        Try
    
            authProvider.Logout()
    
        Catch ex As WebException
    
            MessageBox.Show("Unable to access the authentication service." & _
                Environment.NewLine & "Logging off locally only.", _
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
            ConnectivityStatus.IsOffline = True
            authProvider.Logout()
            ConnectivityStatus.IsOffline = False
    
        End Try
    
        Application.Restart()
    
    End Sub
    
    private void logoutButton_Click(object sender, EventArgs e)
    {
        SaveSettings();
    
        ClientFormsAuthenticationMembershipProvider authProvider =
            (ClientFormsAuthenticationMembershipProvider)
            System.Web.Security.Membership.Provider;
    
        try
        {
            authProvider.Logout();
        }
        catch (WebException ex)
        {
            MessageBox.Show("Unable to access the authentication service." +
                Environment.NewLine + "Logging off locally only.",
                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            ConnectivityStatus.IsOffline = true;
            authProvider.Logout();
            ConnectivityStatus.IsOffline = false;
        }
    
        Application.Restart();
    }
    

로그아웃 기능을 테스트하려면 응용 프로그램을 실행하고 로그온 대화 상자에서 암호 저장을 선택합니다. 그런 다음 응용 프로그램을 종료했다가 다시 시작하여 더 이상 로그인할 필요가 없음을 확인합니다. 마지막으로 로그아웃을 클릭하여 응용 프로그램을 다시 시작합니다.

오프라인 모드에서 사용할 수 있도록 설정

다음 절차에서는 폼에 확인란을 추가하여 사용자가 오프라인 모드로 들어가도록 합니다. 응용 프로그램에서는 static ConnectivityStatus.IsOffline 속성을 true로 설정하여 오프라인 모드를 나타냅니다. 오프라인 상태는 Application.UserAppDataPath 속성으로 나타내는 위치에 있는 로컬 하드 디스크에 저장됩니다. 이는 오프라인 상태가 사용자 및 응용 프로그램 단위로 저장된다는 것을 의미합니다.

오프라인 모드에서는 모든 클라이언트 응용 프로그램 서비스 요청이 서비스에 대해 액세스를 시도하는 대신 로컬 캐시에서 데이터를 검색합니다. 기본 구성의 로컬 데이터에는 암호화된 형태의 사용자 암호가 들어 있어 응용 프로그램이 오프라인 모드에 있는 동안에도 사용자가 로그인할 수 있게 해 줍니다. 자세한 내용은 방법: 클라이언트 응용 프로그램 서비스 구성을 참조하십시오.

응용 프로그램에서 오프라인 모드를 활성화하려면

  1. 솔루션 탐색기의 ClientAppServicesDemo 프로젝트에서 Form1을 선택한 다음 Visual Studio 주 메뉴에서 보기 | 디자이너를 선택합니다.

  2. 디자이너에서 CheckBox 컨트롤을 폼에 추가합니다.

  3. 속성 창에서 workOfflineCheckBox의 (이름) 값과 &Work offline의 텍스트 값을 지정합니다.

  4. 속성 창에서 이벤트 단추를 클릭합니다.

  5. CheckedChanged 이벤트를 선택한 다음 Enter 키를 눌러 이벤트 처리기를 생성합니다.

  6. 생성된 메서드를 다음 코드로 바꿉니다.

    이 코드는 IsOffline 값을 업데이트하고 사용자가 온라인 모드로 돌아오면 자동으로 다시 유효성 검사를 수행합니다. ClientFormsIdentity.RevalidateUser 메서드는 사용자가 명시적으로 로그인할 필요가 없도록 캐시된 자격 증명을 사용합니다. 인증 서비스를 사용할 수 없는 경우 경고 메시지가 나타나고 응용 프로그램은 오프라인 상태를 유지합니다.

    참고

    RevalidateUser 메서드는 편의상 제공된 것으로, 반환 값이 없기 때문에 유효성 재검사가 실패했는지 여부를 나타낼 수 없습니다. 예를 들어 서버에서 사용자 자격 증명이 변경되었으면 유효성 재검사가 실패할 수 있습니다. 이 경우 서비스 호출이 실패한 후 사용자에 대한 유효성을 명시적으로 검사하는 코드를 포함해야 할 수 있습니다. 자세한 내용은 이 연습의 앞부분에 있는 웹 설정 액세스 단원을 참조하십시오.

    유효성 재검사가 끝나면 이 코드는 앞에서 추가한 SaveSettings 메서드를 호출하여 로컬 웹 설정의 변경 사항을 저장합니다. 그런 다음 프로젝트의 Settings 클래스(C#에서는 Properties.Settings.Default, Visual Basic에서는 My.Settings로 각각 액세스)에 대한 Reload 메서드를 호출하여 서버에서 새 값을 검색합니다.

    Private Sub workOfflineCheckBox_CheckedChanged( _
        ByVal sender As Object, ByVal e As EventArgs) _
        Handles workOfflineCheckBox.CheckedChanged
    
        ConnectivityStatus.IsOffline = workOfflineCheckBox.Checked
    
        If Not ConnectivityStatus.IsOffline Then
    
            Try
    
                ' Silently re-validate the user.
                CType(System.Threading.Thread.CurrentPrincipal.Identity,  _
                    ClientFormsIdentity).RevalidateUser()
    
                ' If any settings have been changed locally, save the new
                ' new values to the Web settings service.
                SaveSettings()
    
                ' If any settings have not been changed locally, check 
                ' the Web settings service for updates. 
                My.Settings.Reload()
    
            Catch ex As WebException
    
                MessageBox.Show( _
                    "Unable to access the authentication service. " & _
                    Environment.NewLine + "Staying in offline mode.", _
                    "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                workOfflineCheckBox.Checked = True
    
            End Try
    
        End If
    
    End Sub
    
    private void workOfflineCheckBox_CheckedChanged(
        object sender, EventArgs e)
    {
        ConnectivityStatus.IsOffline = workOfflineCheckBox.Checked;
        if (!ConnectivityStatus.IsOffline)
        {
            try
            {
                // Silently re-validate the user.
                ((ClientFormsIdentity)
                    System.Threading.Thread.CurrentPrincipal.Identity)
                    .RevalidateUser();
    
                // If any settings have been changed locally, save the new
                // new values to the Web settings service.
                SaveSettings();
    
                // If any settings have not been changed locally, check 
                // the Web settings service for updates. 
                Properties.Settings.Default.Reload();
            }
            catch (WebException)
            {
                MessageBox.Show(
                    "Unable to access the authentication service. " +
                    Environment.NewLine + "Staying in offline mode.",
                    "Warning", MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
                workOfflineCheckBox.Checked = true;
            }
        }
    }
    
  7. 다음 코드를 Form1_Load 메서드의 끝에 추가하여 확인란에 현재 연결 상태가 표시되도록 합니다.

    workOfflineCheckBox.Checked = ConnectivityStatus.IsOffline
    
    workOfflineCheckBox.Checked = ConnectivityStatus.IsOffline;
    

이것으로 예제 응용 프로그램이 완성되었습니다. 오프라인 기능을 테스트하려면 응용 프로그램을 실행하고 직원이나 관리자로 로그인한 다음 오프라인으로 작업을 선택합니다. 텍스트 상자에서 값을 수정한 다음 응용 프로그램을 종료합니다. 응용 프로그램을 다시 시작합니다. 로그인하기 전에 작업 표시줄의 알림 영역에서 ASP.NET Development Server 아이콘을 마우스 오른쪽 단추로 클릭한 다음 중지를 클릭합니다. 그런 다음 평상시처럼 로그인합니다. 서버가 실행되고 있지 않을 때도 로그인할 수 있습니다. 텍스트 상자 값을 수정한 다음 종료했다가 다시 시작하여 수정된 값을 확인하십시오.

요약

이 연습에서는 Windows Forms 응용 프로그램에서 클라이언트 응용 프로그램 서비스를 활성화하여 사용하는 방법에 대해 알아보았습니다. 또한 테스트 서버를 설정한 후에 응용 프로그램에 코드를 추가하여 사용자를 인증하고 서버에서 사용자 역할 및 응용 프로그램 설정을 검색했습니다. 뿐만 아니라 연결 기능을 사용할 수 없을 때 응용 프로그램에서 원격 서비스 대신 로컬 데이터 캐시를 사용하도록 오프라인 모드를 활성화하는 방법에 대해서도 살펴보았습니다.

다음 단계

실제 응용 프로그램에서는 이따금 사용할 수 없는 경우가 발생하거나 예고 없이 다운될 수 있는 원격 서버에서 많은 사용자의 데이터에 액세스합니다. 응용 프로그램의 효율성을 높이려면 서버를 사용할 수 없는 상황에 적절히 대처해야 합니다. 이 연습에는 WebException을 catch하고 서비스를 사용할 수 없을 때 오류 메시지를 표시하기 위한 try/catch 블록이 들어 있습니다. 프로덕션 코드에서는 오프라인 모드로 전환하거나, 응용 프로그램을 종료하거나, 특정 기능에 대한 액세스를 거부하는 방식으로 이러한 상황을 처리해야 할 수 있습니다.

응용 프로그램의 보안 수준을 높이려면 배포 전에 응용 프로그램과 서버를 철저하게 테스트해야 합니다.

참고 항목

작업

방법: 클라이언트 응용 프로그램 서비스 구성

연습: ASP.NET 응용 프로그램 서비스 사용

개념

클라이언트 응용 프로그램 서비스 개요

기타 리소스

클라이언트 응용 프로그램 서비스

ASP.NET 웹 사이트 관리 도구

SQL Server용 응용 프로그램 서비스 데이터베이스 만들기 및 구성