login register Sysop! about ME  
qrcode
    최초 작성일 :    2008년 08월 28일
  최종 수정일 :    2008년 08월 28일
  작성자 :    songgun
  편집자 :    songgun(송 원석)
  읽음수 :    23,002

강좌 목록으로 돌아가기

필자의 잡담~

(없음)
IIS 7.0 인스퍼레이션 - 18, (Developing a Module using .NET 번역 및 주해)

다음은 본 번역 문서의 권한에 관한 제반 사항입니다.
  • 본 번역 문서에 대한 모든 저작권은 마이크로소프트사에 있으며, 단순히 IIS 7.0 을 널리 알리고자 하는 개인적인 취지에 의해 번역되어 제공되는 문서입니다.
  • 마이크로소프트사의 요청이 있는 경우 언제라도 게시가 중단될 수 있습니다.
  • 본문에서 제공하는 번역에는 오역이 포함되어 있을 수 있으며, 주해의 내용도 개인적으로 파악한 것으로 마이크로소프트사는 이 내용에 대해 일체의 보장을 하지 않습니다.
  • 본문의 원문은 IIS 개발팀이 제공하는 Developing a Module using .NET 입니다.
서론

다음과 같은 두 가지 방식으로 모듈을 개발하여 IIS7 을 확장할 수 있습니다.:

  1. 관리되는 코드와 ASP.NET 서버 확장 API 를 사용하는 방식.
  2. 네이티브 코드와 IIS7 네이티브 서버 확장 API 를 사용하는 방식.
지금까지는 ASP.NET 요청 처리 파이프라인과 서버의 메인 요청 파이프라인이 별개로 분리되어 있었기 때문에, ASP.NET 모듈의 기능이 제한적일 수 밖에 없었습니다. IIS7 의 통합 파이프라인 아키텍처는 사실상 관리되는 모듈의 기능을 네이티브 모듈과 비슷한 수준까지 강력하게 끌어올렸습니다. 가장 중요한 점은, 관리되는 모듈에 의해 제공되는 서비스들이, ASPX 페이지 등과 같은 ASP.NET 콘텐츠에 대한 요청 뿐만 아니라, 서버에 대한 모든 요청에 적용된다는 사실입니다. 관리되는 모듈은 네이티브 모듈과 동일한 방식으로 구성 및 관리되며, 동일한 처리 단계와 순서로 실행됩니다. 마지막으로, 관리되는 모듈은 ASP.NET 의 기본 기능을 향상시키고 확장하기 위해 요청 처리를 제어하는 폭넓은 작업을 수행할 수 있습니다.

본문에서는 ASP.NET 2.0 멤버쉽 시스템이 제공해주는 강력한 제공자-기반 신원 증명 기반구조와 같이, 임의의 신원 증명 저장소를 사용하여 기본 인증을 수행하는 기능을 구현한 관리되는 모듈을 사용하여 서버를 확장하는 구체적인 방법을 살펴봅니다. 이 모듈은 IIS7 이 기본 제공하는 윈도우 신원 증명 저장소와 밀접하게 결합된 내장 기본 인증 기능을 대체하여, 임의의 신원 증명 저장소를 지원하거나, ASP.NET 2.0 과 함께 제공되는 SQL 서버나 SQL 익스프레스, 또는 액티브 디렉터리 등과 같은 멤버쉽 제공자를 지원하는 기본 인증을 사용할 수 있게 해줍니다. *

본문에서는 다음과 같은 내용들을 살펴봅니다.:

  • ASP.NET API 를 사용하여 관리되는 모듈을 개발해봅니다.
  • 관리되는 모듈을 서버에 배포해봅니다.
만약, IIS7 모듈 및 헨들러 개발에 관한 기본적인 내용들을 살펴보고 싶다면 .NET 프레임워크를 사용하여 IIS7 모듈 및 헨들러 개발하기를 살펴보시기 바랍니다.

그리고, 필자의 블로그 (http://www.mvolo.com/) 에서는 IIS7 모듈을 개발하기 위한 다양한 자료와 팁을 살펴보거나, 여러분들의 응용 프로그램에 적용할 수 있는 여러 가지 IIS7 모듈들을 다운로드 받을 수 있습니다. 예를 들어서, HttpRedirection 모듈을 사용하여 응용 프로그램에 대한 요청 리디렉션하기, DirectoryListingModule 모듈을 사용하여 세련된 IIS 웹 사이트 디렉터리 목록 출력하기, IconHandler 를 사용하여 세련된 ASP.NET 응용 프로그램 파일 아이콘 출력하기, 그리고 IIS 와 ASP.NET 을 사용하여 핫-링크 막기 등을 살펴보시기 바랍니다. **

주의: 본문에서는 C# 으로 작성된 코드가 제공됩니다.

* 다시 간단하게 설명을 정리해보면 이런 것이다. 여러분들도 이미 알고 있는 바와 같이 IIS7 에서도 기본 인증 모듈은 물론 제공된다. 다만, 한 가지 아쉬운 점은 이 기본 인증 모듈은 항상 윈도우 사용자 계정을 기반으로 사용자를 인증한다는 사실이다. 근본적으로, SQL 서버에 저장된 아이디와 비밀번호 같은 다른 사용자 신원 정보를 사용할 수 있는 방법이 없는 것이다. 그래서, 본문에서는 아예 우리들의 입맛에 맞게 모듈을 하나 만들어 버리고, 이 새로운 모듈로 기존의 기본 인증 모듈을 대체해 버리는 방법을 보여준다. 이러한 기능은 IIS7 이전에는 ISAPI 필터를 사용해야만 구현이 가능했던 기능이다.
** 여기에서 말하는 필자란 마이크로소프트 IIS 개발팀의 프로그램 메니저인 Mike Volodarsky 를 말하는 것이다. 번역자가 아니므로 오해가 없기 바란다.


전제조건

본문의 모든 과정을 따라해보기 위해서는 다음과 같은 IIS 기능들이 설치되어 있어야만 합니다.

ASP.NET

윈도우 비스타에서는 제어판을 통해서 ASP.NET 을 설치합니다. 제어판을 열고 "프로그램" - "Windows 기능 사용/사용 안 함"을 실행합니다. 그리고, "인터넷 정보 서비스" - "World Wide Web 서비스" - "응용 프로그램 개발 기능" 노드를 확장하고 "ASP.NET" 항목을 선택합니다.

만약, 롱혼 서버를 사용중이라면, 서버 관리자를 실행하고 "Manage Roles" 노드를 열어서 "Web Server (IIS)" 노드를 선택합니다. "Add role services" 링크 버튼을 클릭한 다음, "Application Development" 노드의 "ASP.NET" 항목을 선택합니다.

기본 인증에 대한 배경 지식

기본 인증은 HTTP1.1 프로토콜 (RFC 2617) 에 정의된 인증 체계의 하나입니다. 기본 인증은 다음과 같이 고수준에서 이루어지는 표준 챌린지 기반 메커니즘을 사용합니다.: *

  1. 브라우저가 특정 URL 에 대한, 신원 정보가 존재하지 않는 요청을 생성합니다.
  2. 만약, 지정한 URL 이 인증을 요구한다면, 서버는 헤더에 401 접근 제한 메시지와 기본 인증 체계를 지원한다는 지시자가 추가된 응답을 생성합니다.
  3. 브라우저가 이 응답을 받으면, 설정 상태에 따라, 사용자 이름과 비밀번호를 입력하는 프롬프트를 출력하고, 이 신원 정보는 다음 요청시에 요청 헤더 내부에 평문으로 포함됩니다.
  4. 마지막으로, 서버는 헤더에 포함된 사용자 이름과 비밀번호를 이용하여 인증을 시도합니다.
주의: 인증 프로토콜에 대한 복잡한 설명은 본문의 범위를 벗어나는 일이기는 하지만, 기본 인증 체계가 사용자 이름과 비밀번호를 평문으로 전송하기 때문에, 보안을 위해서는 SSL 을 필요로 한다는 점은 한 번 깊이 생각해 볼만한 가치가 있습니다. **

기본적으로 IIS7 및 그 하위 버전에는 로컬 계정 저장소에 저장된 윈도우 계정이나, 액티브 디렉터리에 저장된 윈도우 계정을 지원하는 기본 인증 기능이 포함되어 있습니다. 본문에서 우리들이 구현하게 될 모듈은 기본 인증을 사용하여 사용자 인증을 처리하지만, 윈도우 계정이 아닌 ASP.NET 2.0 멤버쉽 서비스를 사용하게 될 것입니다. 이러한 기능은 우리들에게 사용자 정보를 윈도우 계정에 얽매이지 않고 SQL 서버 등과 같은 기존 멤버쉽 제공자에 저장할 수 있는 자유를 줄 것입니다.

* 본문을 번역하면서 가장 고심했던 단어가 바로 이 "챌린지" 라는 단어다. 번역을 하다보면 직접 읽을 때는 문장의 행간을 파악하여 의미를 이해할 수 있지만, 한글로 번역하기는 조금 미묘하게 곤란한 경우가 종종 있다. 이 "챌린지"라는 단어가 바로 그러한데, 단순히 단어만 번역하자면 "시도" 라고 번역될 수 있겠으나, 본문에서는 "챌린지"라는 발음을 그대로 사용한다.
** 기본 인증으로 전송되는 사용자 이름과 비밀번호는 암호화되지 않는다. 단지 Base64 로 인코딩 될 뿐이며, 이는 비단 프로그래머가 아니더라도 약간의 요령만 있으면 쉽게 해석이 가능하다. 따라서, 필자가 근무하는 회사의 주력 솔루션인 전자입찰이나 전자계약 등과 같이 미션 크리티컬한 업무 시스템에는 결코 적당하지 않은 인증 방식이다. 이 문제점을 보완하기 위해서는 반드시 SSL 을 적용하거나 다른 대안을 강구해야만 한다.

그리고, 참고로 동일한 문제점이 FTP 서비스에도 존재하는데, IIS 에서 기본적으로 제공되는 FTP 서비스는 기본 인증 방식을 통해서 인증이 이루어진다. 그런데, 주지한 바와 같이 이 경우 사용자의 신원 정보는 거의 보호를 받을 수 없다. 이를 보안하기 위한 기능이 FTP7 에 비로소 추가되었는데, SSL 에 대한 지원이 바로 그것이다. 이에 대한 보다 자세한 정보는 필자가 번역한 FTP7 관련 문서를 참고하기 바란다.


작업 1: .NET 을 사용한 모듈 개발

이번 작업에서, 우리들은 HTTP1.1 기본 인증 체계를 지원하는 기본 인증 모듈을 개발해보려고 합니다. 이 모듈은 ASP.NET v1.0 시절부터 ASP.NET 모듈 작성을 위해 사용해왔던 패턴과 동일한 표준 ASP.NET 모듈 패턴으로 개발될 것이며, 결과적으로는 IIS7 서버를 확장하게 됩니다. 또한, 구버전의 IIS 를 대상으로 작성된 기존 모듈도 IIS7 에서 사용이 가능할 뿐만 아니라, 해당 모듈을 사용하는 응용 프로그램도 향상된 ASP.NET 통합 모드가 제공하는 강력한 이점들을 누릴 수 있습니다.

주의: 모듈의 전체 코드는 부록 A 에서 제공됩니다.

관리되는 모듈은 System.Web.IHttpModule 인터페이스를 구현한 .NET 클래스입니다. 이 클래스의 가장 중요한 기능은 IIS 요청 처리 파이프라인에서 발생되는 이벤트들 중, 하나 또는 그 이상의 이벤트에 이벤트 헨들러를 등록하고, IIS 가 해당 이벤트에 연결된 모듈의 이벤트 헨들러를 실행할 때, 일련의 의미있는 작업들을 처리하는 것입니다.

그러면, "BasicAuthenticationModule.cs" 라는 이름으로 새로운 소스 파일을 생성하고, 모듈 클래스를 생성합니다. (전체 소스 코드는 부록 A 에서 제공됩니다.):

public class BasicAuthenticationModule : System.Web.IHttpModule

{
    void Init(HttpApplication context)
    {

    }

    void Dispose()
    {

    }
}
먼저, Init 메서드의 가장 중요한 기능은 모듈의 이벤트 헨들러를 적절한 요청 파이프라인 이벤트와 연결하는 것입니다. 각각의 이벤트 헨들러 메서드들은 모듈 클래스로부터 제공되고, 모듈이 제공하고자 하는 실질적인 기능들을 구현하게 됩니다. 이 부분은 뒤에서 더 자세히 살펴보도록 하겠습니다.

그리고, Dispose 메서드는 모듈의 인스턴스가 제거될 때 모듈의 각종 상태를 정리하기 위해 사용됩니다. 그러나, 일반적으로 모듈에서 별도로 해제가 필요한 특정 리소스가 사용되지 않는 한 이 메서드는 구현되지 않는 경우가 많습니다. *

Init()

모듈 클래스를 생성했다면, 먼저 Init 메서드를 구현해야 합니다. 이 메서드가 수행하게 될 유일한 작업은 하나 이상의 요청 파이프라인 이벤트를 등록하는 것입니다. 이 작업은 System.EventHandler 델리게이트의 시그니처를 구현한 모듈 메서드들을, System.Web.HttpApplication 의 인스턴스가 노출하는 이벤트들 중에서 적절한 이벤트에 연결함으로서 이루어집니다.:

public void Init(HttpApplication context)

{
    //
    // Subscribe to the authenticate event to perform the
    // authentication.
    //
    context.AuthenticateRequest += new
        EventHandler(this.AuthenticateUser);

    //
    // Subscribe to the EndRequest event to issue the
    // challenge if necessary.
    //
    context.EndRequest += new
        EventHandler(this.IssueAuthenticationChallenge);
}
여기에서 AuthenticateUser 메서드는 모든 요청에 대해 AuthenticateRequest 이벤트가 발생할 때마다 실행됩니다. 우리들은 요청에 포함된 신원 정보를 사용하여 사용자를 인증하기 위해 이 메서드를 사용할 것입니다.

그리고, IssueAuthenticationChallenge 메서드는 모든 요청에 대해 EndRequest 이벤트가 발생할 때마다 실행됩니다. 이 메서드는 인증 모듈에 의해 요청이 거부되어 인증이 필요할 때마다, 클라이언트에게 기본 인증 챌린지를 발급하는 작업을 담당하게 됩니다.

AuthenticateUser()

그러면, AuthenticateUser 메서드를 구현해보겠습니다. 이 메서드는 다음과 같은 작업을 수행합니다.:

  1. 전송된 요청의 헤더에 기본 인증 정보가 존재하는 경우, 해당 정보를 추출해냅니다. 이 작업의 실제 구현은 ExtractBasicAuthenticationCredentials 메서드를 참고하십시오.
  2. 멤버쉽 (기본 멤버쉽 제공자로 설정된) 을 이용하여 제공된 신원 정보의 유효성을 검증합니다. 이 작업의 실제 구현은 ValidateCredentials 메서드를 참고하십시오.
  3. 인증에 성공하면, 사용자를 증명하는 사용자 보안 주체를 생성하고, 이를 요청과 연결합니다.
만약, 기본 인증 모듈이 성공적으로 사용자의 신원 정보를 얻고 유효성을 검증한다면, 처리 과정의 마지막 부분에서, 추후에 다른 모듈이나 응용 프로그램 코드가 접근 제어에 대한 결정을 내릴때 참고할 수 있는 인증된 사용자의 보안 주체를 생성합니다. 예를 들어서, 파이프라인의 다음 이벤트로 설정되어 있는 URL 인증 모듈은 응용 프로그램에 의해 설정된 인증 규칙을 적용하기 위해, 이때 생성된 사용자 보안 주체를 사용할 수 있습니다.

IssueAuthenticationChallenge()

이번에는 IssueAuthenticationChallenge 메서드를 구현합니다. 이 메서드는 다음과 같은 작업을 수행합니다.:

  1. 요청이 거부되었는지를 파악하기 위해 응답 상태 코드를 점검합니다.
  2. 만약, 요청이 거부되었다면, 응답에 기본 인증 챌린지 헤더를 기록하여 클라이언트측 인증 과정을 유도합니다.
유틸리티 메서드

마지막으로 모듈 내부에서 사용되는 다음과 같은 유틸리티 메서드들을 구현해봅니다.:

  • ExtractBasicCredentials 메서드. 이 메서드는 인증 요청 헤더로부터 기본 인증 체계에 따라 기본 인증 신원 정보를 추출합니다.
  • ValidateCredentials 메서드. 이 메서드는 멤버쉽을 사용하여 사용자의 신원 정보 유효성을 검증합니다. 멤버쉽 API 는 기반 신원 증명 저장소를 추상화해주고, 구성 설정을 통해 멤버쉽 제공자를 추가하거나 제거하여 신원 증명 저장소 구현을 설정할 수 있게 해줍니다.
주의: 본문에서는 멤버쉽을 통한 유효성 검사에 대해서는 설명하지 않으며, 모듈에서는 단순하게 사용자 이름과 비밀번호가 모두 "test" 인지 여부만 점검합니다. 이는 본문이 다루는 핵심적인 내용에 대해서만 집중하기 위한 것으로, 실제 제품 배포시에는 이렇게 하면 안됩니다. 응용 프로그램의 멤버쉽 제공자를 구성하고, 주석처리 되어 있는 ValidateCredentials 메서드 내의 멤버쉽 관련 코드에서 주석처리를 제거하기만 하면 간단하게 멤버쉽-기반 신원 정보 검증을 활성화할 수 있습니다. 이 방법에 대한 보다 자세한 설명은 부록 C 에서 제공됩니다. **

* 모듈이라고 해서 Dispose 메서드를 구현할때 적용되는 특별한 규칙같은 것은 존재하지 않는다. 일반적인 클래스를 구현할 때와 마찮가지로 관리되지 않는 리소스나, 사용이 끝난 즉시 해제할 필요가 있는 리소스가 모듈에서 사용되는 경우에만 Dispose 메서드를 구현하면 된다.
** 본문의 주제는 어디까지나 기본 인증이 아닌 .NET 으로 개발한 모듈을 사용하여 IIS7 의 기능을 확장하는 방법이라는 점을 기억하기 바란다.


작업 2: 응용 프로그램에 모듈 배포하기

이번에는 이전 단계에서 작성한 모듈을 응용 프로그램에 배포해 보겠습니다.

응용 프로그램에 배포하기

응용 프로그램에 모듈을 배포합니다. 다음은 배포시 선택할 수 있는 옵션들입니다.:

  • 모듈을 구현한 소스 파일을 응용 프로그램의 /App_Code 디렉터리에 복사합니다. 이 방식은 모듈을 컴파일할 필요가 없으며, 응용 프로그램이 시작될 때 ASP.NET 이 자동적으로 모듈을 컴파일하고 로드합니다. 별다른 처리없이 단지 소스 코드를 BasicAuthenticationModule.cs 라는 이름으로 응용 프로그램의 /App_Code 디렉터리에 저장합니다. 다른 방식에 익숙하지 않다면 이 방식을 선택하면 됩니다.
  • 모듈을 별도의 어셈블리로 컴파일하고, 응용 프로그램의 /BIN 폴더에 복사합니다. 이 방식은 응용 프로그램에서 모듈을 사용하고는 싶지만, 모듈의 소스 코드는 포함시키고 싶지 않을 때 선택할 수 있는 가장 일반적인 방법입니다. 다음 명령어를 명령 프롬프트상에서 실행시키면 모듈 소스 파일을 컴파일 할 수 있습니다.:

    <PATH_TO_FX_SDK>csc.exe /out:BasicAuthenticationModule.dll /target:library BasicAuthenticationModule.cs

    여기서 <PATH_TO_FX_SDK> 는 CSC.EXE 컴파일러가 위치한 .NET 프레임워크 SDK 의 경로입니다.
  • 모듈을 강력한 이름의 어셈블리로 컴파일하고, GAC 에 등록합니다. 이 방식은 하나의 머신에서 모듈을 사용하는 복수의 응용 프로그램을 운영하고자 하는 경우 유용합니다. 강력한 이름의 어셈블리를 구축하는 방법에 대한 보다 자세한 내용은 MSDN 문서를 참고하시기 바랍니다.
그리고, 응용 프로그램의 Web.config 파일 구성 설정을 변경하여 모듈을 구성하기 전에, 먼저 기본적으로 서버 수준에서 잠겨져 있는 일부 구성 설정 섹션의 잠금을 해제해야만 합니다. 권한이 상승된 명령 프롬프트상에서 다음의 명령어를 실행합니다. (시작 메뉴에서 명령 프롬프트를 마우스 오른쪽 버튼으로 클릭하고 "관리자 권한으로 실행" 을 선택합니다.): *

%windir%\system32\inetsrv\APPCMD.EXE unlock config /section:windowsAuthentication

%windir%\system32\inetsrv\APPCMD.EXE unlock config /section:anonymousAuthentication
이 명령어를 실행시키면, 응용 프로그램의 Web.config 파일에 해당 구성 설정 섹션을 정의할 수 있게 됩니다.

이제 모듈이 실행되도록 응용 프로그램에 모듈을 구성합니다. 새로운 모듈을 활성화시키고 사용하기 위해 필요한 구성 설정을 포함하고 있는 새로운 Web.config 파일을 생성합니다. 이 파일에 다음의 내용들을 추가하고 응용 프로그램의 루트에 저장합니다. (만약, 기본 웹 사이트의 루트 응용 프로그램을 테스트에 사용중이라면, 그 경로는 %systemdrive%\inetpub\wwwroot\web.config 파일이 됩니다.)

<configuration> 

    <system.webServer>
        <modules>
        </modules>
        <security>
            <authentication>
                <windowsAuthentication enabled="false"/>
                <anonymousAuthentication enabled="false"/>
            </authentication>
        </security>
    </system.webServer>
</configuration>
그리고, 새로운 기본 인증 모듈을 활성화시키기 전에, 다른 IIS 인증 모듈들을 모두 비활성화시키는 것이 좋습니다. 기본적으로는 윈도우 인증과 익명 인증만 활성화되어 있습니다. 우리들은 웹 브라우저가 윈도우 신원 정보와 익명 사용자로 인증을 시도하는 상황을 원하지 않기 때문에, 윈도우 인증 모듈과 익명 인증 모듈을 모두 비활성화시킬 것입니다.

이제, 응용 프로그램에 의해서 로딩될 모듈 목록에 우리들의 새로운 모듈을 추가함으로서, 모듈을 활성화시킬 수 있습니다. 이를 위해서, 다시 한 번 Web.config 파일을 열고 <modules> 태그에 다음 항목을 추가합니다.:

<add name="MyBasicAuthenticationModule" type="IIS7Demos.BasicAuthenticationModule" />
아니면, IIS7 관리자 도구나 APPCMD.EXE 명령 프롬프트 도구를 사용하여 응용 프로그램에 모듈을 배포할 수도 있습니다. 지금까지 설명한 내용들이 반영된 응용 프로그램의 Web.config 파일의 최종 내용은 부록 B 에 제공됩니다. 축하합니다, 이제 사용자 정의 기본 인증 모듈의 구성이 모두 끝났습니다.

이제 테스트를 해보겠습니다! 인터넷 익스플로러를 열고, 다음과 같이 응용 프로그램에 대한 요청을 작성합니다.: **

http://localhost/

그러면, 아마도 여러분들은 기본 인증 로그인 대화 상자를 만나게 될 것입니다. 로그인을 해보려면 "사용자 이름:" 필드와 "암호:" 필드에 "test" 를 입력하십시오. 만약, 응용 프로그램에 HTML 이나 JPG, 또는 다른 어떤 종류의 컨텐츠들이 추가되더라도, 새로운 기본 인증 모듈에 의해 보호된다는 점을 기억하시기 바랍니다.

* IIS7 에서 구성 설정 섹션이 서버 수준에서 잠겨 있다는 얘기는, 간단하게 말해서 해당 구성 설정 섹션은 applicationHost.config 파일에서만 설정이 가능하다는 의미다. 따라서, 기본적으로 서버 수준에서 잠겨 있는 구성 설정 섹션은 관리자만 설정이 가능하다고 보면 된다. 그러나, 관리자가 본문에서 설명하는 명령어를 실행하는 등의 방법으로 해당 구성 설정 섹션의 잠금을 풀어주면 web.Config 파일에서도 설정이 가능해진다.

이 기능을 기능 위임이라고 하는데, IIS7 에서 도입된 분산 구성 설정 시스템의 가장 중요한 특징 중 하나이다. 이러한 잠금 관련 설정은 본문에서 설명하고 있는 명령어를 실행하는 방법 외에도 IIS 관리자를 통해서도 설정이 가능하다. IIS 관리자를 실행시키고 트리뷰에서 루트 노드를 선택한 다음, 관리 영역의 기능 위임 아이콘을 더블 클릭해보면, 위의 명령어를 실행시키기 전에는 윈도우 인증과 익명 인증이 다음과 같이 읽기 전용으로 설정되어 있을 것이다.

그러나, 명령어를 실행시키고 새로 고침을 해보면 다음과 같이 읽기/쓰기로 설정이 변경되어 있다.

물론 당연한 얘기겠지만, 방금 얘기한 바와 같이 이 화면에서 직접 기능 위임 설정을 변경할 수도 있으며, 설정을 변경하고자 하는 기능을 선택하고 작업 영역에서 원하는 링크 버튼을 클릭하기만 하면 된다.
** 물론 이 주소는 각자 테스트에 사용한 웹 응용 프로그램에 따라 달라질 것이다. 필자가 테스트 해본 바에 따르면 비스타상에서 다음과 같은 다음과 같은 로그인 대화 상자가 나타났으며 모든 동작이 정상적으로 이루어졌다.


요약

본문에서는 응용 프로그램을 위한 사용자 정의 관리되는 모듈을 작성 및 배포하는 방법과, 해당 모듈이 응용 프로그램의 모든 요청에 대해 서비스되도록 활성화시키는 방법을 살펴보았습니다.

그리고, 여러분들은 관리되는 코드를 사용한 서버 컴포넌트 개발의 강력함을 직접 목격했습니다. 이는 윈도우 신원 증명 저장소에 구애받지 않는 기본 인증 서비스를 개발할 수 있도록 해줍니다.

만약, 여러분들이 더욱 다양한 시도를 해보고 싶다면, 이 모듈을 구성 설정에 기반한 신원 증명 저장소를 지원하는 ASP.NET 2.0 멤버쉽 응용 프로그램 서비스를 이용하도록 구성할 수도 있습니다. 보다 자세한 정보는 부록 C 를 참고하십시오. *

그리고, 필자의 블로그 (http://www.mvolo.com/) 에서는 IIS7 모듈을 개발하기 위한 다양한 자료와 팁을 살펴보거나, 여러분들의 응용 프로그램에 적용할 수 있는 여러 가지 IIS7 모듈들을 다운로드 받을 수 있습니다. 예를 들어서, HttpRedirection 모듈을 사용하여 응용 프로그램에 대한 요청 리디렉션하기, DirectoryListingModule 모듈을 사용하여 세련된 IIS 웹 사이트 디렉터리 목록 출력하기, IconHandler 를 사용하여 세련된 ASP.NET 응용 프로그램 파일 아이콘 출력하기, 그리고 IIS 와 ASP.NET 을 사용하여 핫-링크 막기 등을 살펴보시기 바랍니다.

* 본문의 원문은 마이크로소프트의 IIS 개발팀에 의해서 작성된 문서이기 때문에, 반복해서 ASP.NET 2.0 멤버쉽 서비스를 강조하고 있다. 그러나, 본문을 읽어보신 분들은 아시겠지만, 멤버쉽 서비스를 사용하지 않고 각자 개발한 코드를 사용한다고 해서 문제가 될 것은 전혀 없다. 오히려 국내 사정을 감안해 본다면 멤버쉽 서비스가 사용되는 경우가 더 드물 것으로 생각된다.


부록 A: 기본 인증 모듈 소스 코드

보다 간단한 배포를 원하신다면 다음의 소스 코드를 BasicAuthenticationModule.cs 라는 이름으로 응용 프로그램의 /App_Code 디렉터리에 저장하십시오.

주의: 만약 메모장을 사용중이라면, 파일명이 BasicAuthenticationModule.cs.txt 등과 같이 저장되는 것을 피하기 위해 "다른 이름으로 저장" 메뉴를 사용하시기 바랍니다.

#region Using directives

using System;
using System.Collections;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Security.Principal;
using System.IO;
#endregion

namespace IIS7Demos
{
    ///
    /// This module performs basic authentication.
    /// For details on basic authentication see RFC 2617.
    ///
    /// The basic operational flow is:
    ///
    ///    On AuthenticateRequest:
    ///        extract the basic authentication credentials
    ///        verify the credentials
    ///        if succesfull, create the user principal with these credentials
    ///
    ///    On SendResponseHeaders:
    ///        if the request is being rejected with an unauthorized status code (401),
    ///        add the basic authentication challenge to trigger basic authentication.
    ///       
    ///

    public class BasicAuthenticationModule : IHttpModule
    {
        #region member declarations
        public const String    HttpAuthorizationHeader = "Authorization";  // HTTP1.1 Authorization header
        public const String    HttpBasicSchemeName = "Basic"; // HTTP1.1 Basic Challenge Scheme Name
        public const Char      HttpCredentialSeparator = ':'; // HTTP1.1 Credential username and password separator
        public const int        HttpNotAuthorizedStatusCode = 401; // HTTP1.1 Not authorized response status code
        public const String    HttpWWWAuthenticateHeader = "WWW-Authenticate"; // HTTP1.1 Basic Challenge Scheme Name
        public const String    Realm = "demo"; // HTTP.1.1 Basic Challenge Realm
        #endregion

        #region Main Event Processing Callbacks
        public void AuthenticateUser(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
            String userName = null;
            String password = null;
            String realm = null;
            String authorizationHeader = context.Request.Headers[HttpAuthorizationHeader];

            //
            // Extract the basic authentication credentials from the request
            //
            if (!ExtractBasicCredentials(authorizationHeader, ref userName, ref password))
                return;

            //
            // Validate the user credentials
            //
            if (!ValidateCredentials(userName, password, realm))
                return;

            //
            // Create the user principal and associate it with the request
            //
            context.User = new GenericPrincipal(new GenericIdentity(userName), null);
        }
     
        public void IssueAuthenticationChallenge(Object source, EventArgs e)
        {
            HttpApplication application = (HttpApplication)source;
            HttpContext context = application.Context;
     
            //
            // Issue a basic challenge if necessary
            //
            if (context.Response.StatusCode == HttpNotAuthorizedStatusCode)
            {
                context.Response.AddHeader(HttpWWWAuthenticateHeader, "Basic realm =\"" + Realm + "\"");
            }
        }
        #endregion

        #region Utility Methods
        protected virtual bool ValidateCredentials(String userName, String password, String realm)
        {
            //
            //  Validate the credentials using Membership (refault provider)
            //

            // NOTE: Membership is commented out for clarity reasons. 

            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // WARNING: DO NOT USE THE CODE BELOW IN PRODUCTION
            // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

            // return Membership.ValidateUser(userName, password);
            if (userName.Equals("test") && password.Equals("test"))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        protected virtual bool ExtractBasicCredentials(String authorizationHeader, ref String username, ref String password)
        {
            if ((authorizationHeader == null) || (authorizationHeader.Equals(String.Empty)))
                return false;

            String verifiedAuthorizationHeader = authorizationHeader.Trim();

            if (verifiedAuthorizationHeader.IndexOf(HttpBasicSchemeName) != 0)
                return false;

            // get the credential payload
            verifiedAuthorizationHeader = verifiedAuthorizationHeader.Substring(HttpBasicSchemeName.Length, verifiedAuthorizationHeader.Length - HttpBasicSchemeName.Length).Trim();

            // decode the base 64 encodeded credential payload
            byte[] credentialBase64DecodedArray = Convert.FromBase64String(verifiedAuthorizationHeader);
            UTF8Encoding encoding = new UTF8Encoding();
            String decodedAuthorizationHeader = encoding.GetString(credentialBase64DecodedArray, 0, credentialBase64DecodedArray.Length);

            // get the username, password, and realm
            int separatorPosition = decodedAuthorizationHeader.IndexOf(HttpCredentialSeparator);
            if (separatorPosition <= 0)
                return false;
     
            username = decodedAuthorizationHeader.Substring(0, separatorPosition).Trim();
            password = decodedAuthorizationHeader.Substring(separatorPosition + 1, (decodedAuthorizationHeader.Length - separatorPosition - 1)).Trim();
 
            if (username.Equals(String.Empty) || password.Equals(String.Empty))
                return false;

            return true;
        }
        #endregion
     
        #region IHttpModule Members
        public void Init(HttpApplication context)
        {
            //
            // Subscribe to the authenticate event to perform the
            // authentication.
            //
            context.AuthenticateRequest += new
                EventHandler(this.AuthenticateUser);

            //
            // Subscribe to the EndRequest event to issue the
            // challenge if necessary.
            //
            context.EndRequest += new
                EventHandler(this.IssueAuthenticationChallenge);
        }

        public void Dispose()
        {
            //
            // Do nothing here
            //
        }

        #endregion
    }
}
부록 B: 기본 인증 모듈을 위한 Web.config

다음의 구성 설정을 여러분들의 응용 프로그램 루트의 Web.config 파일에 저장합니다.:

<configuration>

    <system.webServer>
        <modules>
            <add name="MyBasicAuthenticationModule"
                  type="IIS7Demos.BasicAuthenticationModule" />
        </modules>
        <security>
            <authentication>
                <windowsAuthentication enabled="false"/>
                <anonymousAuthentication enabled="false"/>
            </authentication>
        </security>
    </system.webServer>
</configuration>
부록 C: 멤버쉽 구성

ASP.NET 2.0 멤버쉽 서비스는 대부분의 인증 및 접근 제어 체계에서 요구되는, 신원 증명 유효성 검증과 사용자 관리 기능을 응용 프로그램이 신속하게 구현할 수 있도록 도와줍니다. 멤버쉽은 응용 프로그램의 코드를 실질적인 신원 증명 저장소 구현과 격리시켜주며, 기존 신원 증명 저장소와의 통합을 위한 몇 가지 옵션을 제공해줍니다.

본문의 모듈 예제에서 멤버쉽의 이점을 이용하려면, 단지 멤버쉽의 기능을 호출하는 부분에 적용된 주석을 제거하기만 하면 됩니다. 즉, ValidateCredentials 메서드에서 ValidateUser 메서드를 호출하는 부분의 주석을 제거하고, 응용 프로그램의 멤버쉽 제공자를 구성합니다. 멤버쉽을 구성하는 방법에 대한 보다 자세한 정보는 이 MSDN 문서를 참고하시기 바랍니다.


authored by


 
 
.NET과 Java 동영상 기반의 교육사이트

로딩 중입니다...

서버 프레임워크 지원 : NeoDEEX
based on ASP.NET 3.5
Creative Commons License
{5}
{2} 읽음   :{3} ({4})