^(코딩캣)^ = @"코딩"하는 고양이;
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #5 [完]
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #5 (완결) HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2..
Microsoft Windows/Win32 도움말 연동
2018. 11. 19. 18:06

HLP 형식의 윈도우 도움말 제작하기 #5 [完]

Microsoft Windows/Win32 도움말 연동
2018. 11. 19. 18:06

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #5 (완결)


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

WinAPI에서 hlp 도움말 호출하기


WinAPI에서 .hlp 파일 내의 내용을 띄워주기 위해서는 .hlp 파일을 구성하는 각 파일마다 프로그램적으로 구분 가능한 일련번호가 부여되어야 한다. 프로젝트 화면에서 [Map...] 버튼을 누른다. "Map" 대화상자가 뜨면 [Add...] 버튼을 눌러 "App Map Entry" 대화상자를 연다.

"Topic ID:"에는 .rtf 파일에서 '#' 각주로 지정한 문서의 ID를 적고, "Mapped numeric value:"에는 .hlp 파일 내에서 중복되지 않는 유일한 값을 임의로 부여한다. "Comment:"에는 간단한 설명을 붙일 수 있다.

 

프로젝트 화면에 [MAP] 항목이 새로 나타나면서 위에서 적었던 내용들이 나타난다면 컴파일한다.

 

여기서부터는 코딩이 시작된다. Visual C++를 실행한다. Win32 Application을 선택하여 새로 만든다.

 

소스 파일이 있는 경로와 출력 파일(.exe 파일)이 있는 경로에 각각 Help Workshop에서 만든 .cnt 파일과 .hlp 파일을 붙여넣는다.

 

WinAPI로 버튼을 하나 만든 다음, 버튼을 클릭 시 메시지를 처리하는 부분에서 아래의 함수를 호출해본다.

WinHelp(소유주가 되는 창의 핸들, TEXT(".hlp파일명"), HELP_CONTEXT, 보여줄 문서의 일련번호);

 

이 함수의 원형은 다음과 같다. 성공하면 TRUE를 반환하고 그렇지 않으면 FALSE를 반환한다.

BOOL WinHelp(
    HWND      hWndMain,
    LPCTSTR   lpszHelp,
    UINT      uCommand,
    ULONG_PTR dwData
);

 

만일 이 함수를 C# 언어에서 사용하고자 하면, 다음과 같이 외부함수를 정의한다. 아래의 정의는 MS의 공식적인 변환은 아니며 소스코드의 특성에 따라 커스터마이징이 가능하다.

[DllImport("user32.dll", CharSet=CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WinHelp(
    [MarshalAs(UnmanagedType.SysInt)] IntPtr hWndMain,
    [MarshalAs(UnmanagedType.LPTStr)] string lpszHelp,
    [MarshalAs(UnmanagedType.SysUInt)] int uCommand,
    [MarshalAs(UnmanagedType.SysInt)] IntPtr dwData
);

 

첫 번째 매개변수는 대체로 NULL을 쓰면 되고, 네 번째 매개변수는 Help Workshop의 Map 대화상자에서 부여된 일련번호를 입력한다.

 

버튼을 클릭 시 해당 내용이 보여지는 것을 확인할 수 있다.

 

네 번째 매개변수를 바꿈으로써 상황에 맞는 적절한 도움말을 보여줄 수 있다.

 

Epilogue


이것으로 HLP 형식의 도움말 파일을 생성하고 Windows API와 연동하는 방법에 대해 마친다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #4
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #4 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:55

HLP 형식의 윈도우 도움말 제작하기 #4

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:55

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #4


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

일반 링크 만들기


이번에는 도움말 본문에 링크를 만들어서 클릭하면 해당 문서로 이동하는 기능을 넣어보겠다. 먼저 도움말 파일의 개요를 보여 줄 예제 파일을 아래와 같이 작성한다.

 

파일 ID는 ID_HELP_ABSTRACT, 키워드는 '예제 도움말 파일의 개요 파일'로 지정한다.

 

파일명은 abstract, 파일형식은 서식 있는 텍스트(*.rtf)로 지정하여 저장한다.

 

이전 단계와 마찬가지로 [Files...] 버튼을 눌러 abstract.rtf 파일을 프로젝트에 추가한다.

 

색인 파일(project.cnt)도 함께 열어 이전 단계와 마찬가지로 abstract.rtf에 대한 항목을 추가한다.

 

도움말 생성 프로젝트에 파일 추가가 완료되면 index.rtf를 열어 링크를 삽입한다. 링크를 삽입하고 싶은 문단의 끝에 클릭 시 전환하게 될 문서의 ID를 "띄어쓰기 없이" 곧바로 적는다. 여기서는 클릭 시 ID_HELP_ABSTRACT의 ID가 붙은 문서가 보여져야 하므로 "1. 개요ID_HELP_ABSTRACT"와 같이 문단 끝에 곧바로 이 ID를 적어야 한다.

 

링크를 넣을 문구인 "1. 개요"까지만 선택한 후 마우스 오른쪽 버튼을 클릭한다. 다음 [단락(P)...] 메뉴를 클릭한다.

 

"효과" 영역 중 [취소선(K)] 버튼에 체크하여 선택한 문구가 "1. 개요"와 같이 취소선이 그어지게 설정한 다음 [확인] 버튼을 누른다.

 

이번에는 클릭 시 링크될 대상으로서 적은 ID_HELP_ABSTRACT에 대하여 블록을 지정하고 선택 후 마우스 오른쪽 버튼을 눌러 [단락(P)...] 메뉴를 클릭한다.

 

"효과" 영역 중 [숨김(H)] 버튼에 체크하고 [확인] 버튼을 누른다.

 

아래와 같이 ID가 사라지고, 링크할 텍스트에 취소선이 그어져있으면 된다.

 

숨겨진 텍스트로 된 링크 ID를 확인 또는 수정하고자 할 때는 [리본] 버튼 클릭 후 [Word 옵션(I)] 버튼을 클릭한다.

 

[표시] 버튼을 눌러 [숨겨진 텍스트(D)] 항목에 체크한 후 [확인] 버튼을 누른다.

 

아래와 같이 숨겨졌던 ID가 밑줄 표시된 채 보여질 것이다.

 

이제 프로젝트를 컴파일해보자. Help Workshop 컴파일러가 링크를 감지하여 "1 Jump"를 표시하는 것을 볼 수 있다.

 

.hlp 파일을 실행했을 때 취소선 서식을 넣었던 텍스트가 링크로 나타나는 것을 볼 수 있다.

 

이 링크를 클릭 시 해당 ID의 RTF 문서가 보여지고 [뒤로(B)] 버튼이 활성화 됨을 확인할 수 있다.

 

팝업 링크 만들기


이번에는 copyright.rtf 로 저작권 관련 내용을 적어서 도움말에 팝업 형태로 띄워보겠다. 예시 파일을 작성해본다.

 

'#' 각주에는 이 문서의 ID로 ID_HELP_COPYRIGHT를 부여하고, 'K' 각주에는 "이 예제 도움말 파일의 저작권"이라는 문구를 적어보겠다.

 

프로젝트로 가서 [Files...] 버튼을 눌러 copyright.rtf를 추가하고...

 

목차 파일에도 [Add Below...] 버튼을 눌러 저작권 항목을 추가한다.

 

링크를 삽입할 index.rtf를 열어 "5. 저작권" 글자 뒤에 띄어쓰기 없이 copyright.rtf의 ID인 ID_HELP_COPYRIGHT를 적는다.

 

링크를 넣을 텍스트만 블록을 설정한 후 마우스 오른쪽 버튼을 눌러 [글꼴(F)...] 메뉴를 클릭하고,

 

"밑줄 스타일(U):"의 옵션 중 실선을 클릭하여 평범한 밑줄을 넣는다. 그 다음 [확인] 버튼을 누른다.

 

마찬가지로 ID도 블록을 정해 글꼴 옵션에서 숨겨진 텍스트를 클릭한다.

 

아래와 같이 만들면 완성이다.

 

프로젝트로 돌아가 도움말 파일을 컴파일 해 본다. 앞서 만든 링크와 함께, Help Workshop 컴파일러가 두 개의 링크를 감지하여 "2 Jumps"가 뜨는 것을 볼 수 있다.

 

생성된 .hlp 파일을 실행하면 "5. 저작권"에 밑줄이 그어진 것을 볼 수 있다. 이를 클릭해보면...

아래와 같이 팝업 형태로 내용이 보여지게 된다.

 

Epilogue


다음 포스트에서는 만들어진 .hlp 파일을 이용해 WinAPI에서 불러올 수 있도록 해보겠다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #3
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #3 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:41

HLP 형식의 윈도우 도움말 제작하기 #3

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 21:41

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #3


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

문서에 식별 ID 부여하기


먼저, 각 문서별로 hlp 파일 내에서 식별할 수 있는 ID를 부여한다. [참조]-[각주] 카테고리 옆에 달린 작은 단추를 클릭한다.

 

[각주 및 미주] 대화상자가 뜬다. "위치"는 "각주(F):"를 선택하고, "서식"에는 "사용자 지정 표시(U):" 옆의 텍스트상자에 '#'을 입력한다. 그리고 [삽입(I)] 버튼을 누른다.

 

페이지 하단 각주 편집창으로 화면이 이동하는데, 여기에 이 문서의 고유 ID를 각자 알아서 지정하면 된다. 예를 들면, 이 문서에 ID_HELP_INDEX라는 ID를 부여할 수 있다.

 

Help Workshop으로 돌아가 우선 컴파일을 한다. 생성 결과에는 아직 아무런 차이도 보이지 않음을 확인할 수 있다.

 

문서에 색인 정보 추가하기


도움말의 '색인' 창을 통해 이 문서로 접근해오려면, 어떤 단어를 검색했을 때 이 문서가 나타나게 할 지를 지정하는 방법이 필요하다. 이를 위해 [참조]-[각주] 카테고리 옆에 달린 작은 단추를 다시 클릭하여 또 다른 각주를 추가한다.

 

이번에는 "사용자 지정 표시(U):" 텍스트 입력창에 Keyword의 약자인 'K'를 입력하고 [삽입(I)]를 클릭한다.

 

각주 편집으로 화면이 이동하면 이 페이지의 목적을 묘사할 수 있는 적절한 문구를 삽입한다.

 

Help Workshop에서 컴파일을 해 본다. 'K' 각주에 의해 아래 표시와 같이 "1 Keyword"가 뜸을 확인할 수 있다.

 

결과물을 확인한다. 전에는 비활성화 상태였던 [색인(I)] 단추가 활성화되어있음을 확인할 수 있다. 이를 클릭한다. [색인] 탭에서 'K' 각주에 적은 문구가 나타날 것이다.

 

목차 삽입하기


이번에는 목차를 삽입한다. Help Workshop 화면에서 [File]-[New] 메뉴를 클릭한다. 대화상자가 뜨면 [Help Contents]를 선택하고 [OK] 버튼을 누른다.

 

목차를 편집할 수 있는 화면으로 바뀌면서 새 목차 파일이 생성됨을 확인할 수 있다.

 

먼저 "Default filename (and window):" 칸에는 지금 컴파일에 의해 생성되고 있는 hlp 파일 이름을 적는다. "Default title:"에는 목차 및 색인 화면 상단 타이틀 바에서 보여질 제목을 적는다.

 

그 다음 [Add Above...] 버튼을 누른다. "Edit Contents Tab Entry" 대화상자가 뜬다. 대주제를 삽입하기 위해 Heading을 선택 후 "Title:" 텍스트박스에 대주제를 적는다. [OK] 버튼을 누른다.

 

아래와 같이 대주제가 삽입되었다.

 

소주제를 삽입하고 싶은 위치에 항목을 선택한 후 [Add Above] 또는 [Add Below]를 눌러 소주제를 삽입할 수 있다. 이 소주제가 우리가 작성하고 있는 RTF 파일로 연결될 것이다. "Edit Contents Tab Entry" 대화상자에서 Topic을 선택한 다음, "Title:"에는 소주제의 명칭을 적고, "Topic ID:"에는 RTF 파일에서 '#' 각주로 지정한 문서의 식별 ID를 적는다. 그리고 OK를 누른다.

 

아래와 같이 대주제 아래 소주제가 삽입되었음을 확인할 수 있다.

 

이제 이 목차를 저장한다. 파일명은 반드시 .hlp 파일과 같게 적고, 확장자는 .cnt여야 한다. 나중에 이 파일은 .hlp파일과 함께 배포되어야 한다.

 

목차 파일이 생성된 후에는 hlp 파일을 더블클릭하였을 때, RTF 문서의 내용이 그대로 출력되지 않고 아래와 같이 목차 및 색인 대화상자가 우선 뜨게 된다.

 

 

목차(C) 버튼을 눌렀을 때 아래와 같이 목차 화면이 뜬다면 성공이다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #2
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #2 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 19:43

HLP 형식의 윈도우 도움말 제작하기 #2

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 19:43

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #2


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

1. 미디어 삽입


이전 포스트에 이어서 이번에는 rtf 파일에 표와 그림을 삽입하여 도움말 파일을 제작한다.

1-1. 표 삽입


Microsoft Word의 [삽입]-[표]-[표] 메뉴를 클릭하여 표를 삽입한다.

 

아래와 같이 표에 적절한 내용을 채운다.

 

Help Workshop으로 돌아가 컴파일한 후 결과를 확인한다. 표의 테두리가 사라져 있음을 확인할 수 있다. hlp 형식의 도움말 파일은 표의 테두리 모양까지 지원하지는 않기 때문에 이렇게 보인다.

 

1-2. 그림 삽입


이번에는 그림을 삽입한다. 그림을 복사하여 워드에 직접 붙여넣기하면 된다. 일반적인 문서 작성과 다르지 않다.

 

만일 구 버전의 Microsoft Word(2007 버전 미만)를 사용중이라면 컴파일된 hlp 파일에서 이와 같이 붙여넣기로 삽입된 그림이 보이지 않을 수 있다. 이 때는 rtf 파일과 같은 폴더 안에 그림 파일을 생성한 후...

 

[삽입]-[일러스트레이션]-[그림] 메뉴를 클릭하여 그림 파일을 삽입한다.

 

컴파일한 hlp 결과이다.

 

Epilogue


이번 포스트에서는 매우 간단한 내용을 다루어보았다. 다음 포스트에서는 "색인과 목차" 기능에 대해 알아보겠다.

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
HLP 형식의 윈도우 도움말 제작하기 #1
HLP 형식의 윈도우 도움말 제작하기 본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다. HLP 형식의 윈도우 도움말 제작하기 #1 HLP 형식의 윈도우 도움말 제작하기 #2 HLP 형식의 윈도우 도움말 제작하기 #3 HLP 형식의 윈도우 도움말 제작하기 #4 HLP 형식의 윈도우 도움말 제작하기 #5 [完] HLP 형식의 윈도우 도움말 제작하기 #1 HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, ..
Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 17:47

HLP 형식의 윈도우 도움말 제작하기 #1

Microsoft Windows/Win32 도움말 연동
2018. 11. 18. 17:47

HLP 형식의 윈도우 도움말 제작하기


본 시리즈에서는 윈도우 도움말 형식 중 하나인 HLP 형식의 도움말을 생성하기 위한 방법에 대해 정리한다. 참고로 HLP 파일은 Windows XP까지만 열기가 지원된다.

  1. HLP 형식의 윈도우 도움말 제작하기 #1
  2. HLP 형식의 윈도우 도움말 제작하기 #2
  3. HLP 형식의 윈도우 도움말 제작하기 #3
  4. HLP 형식의 윈도우 도움말 제작하기 #4
  5. HLP 형식의 윈도우 도움말 제작하기 #5 [完]

HLP 형식의 윈도우 도움말 제작하기 #1


HLP 도움말은 Windows 3.1부터 Windows XP까지 지원하던 도움말 형식으로서, 내부적으로는 여러개의 RTF 문서 파일로 이루어져 있다. Windows Vista 이후에 출시되는 Windows 운영체제(Vista, 2008, 7, 2010, 8, 2012, 8.1, 10, ...)에서는 공식적으로 지원하지는 않는다. 이번 시리즈에서는 HLP 도움말을 제작하고, WinAPI에서 이를 불러오는 방법까지 알아보겠다.

준비물: 1. Windows XP 또는 그 이전 버전 운영체제, 2. Microsoft Word (아무 버전이나), 3. Microsoft Visual Studio 6.0

 

RTF 문서 준비하기


Microsoft Word를 켜고 아래와 같이 예제 문서를 작성해본다. 예제 문서니까 이것저것 서식도 마음대로 넣어보는 것이 가능하다.

 

저장할 때 파일 형식은 반드시 서식 있는 텍스트 또는 서식 있는 텍스트 (*.rtf)으로 지정한다.

 

HLP 문서 생성하기


[시작] 버튼-[모든 프로그램]-[Microsoft Visual Studio 6.0]-[Microsoft Visual Studio 6.0 도구들]-[Help Workshop]을 클릭한다.

 

프로젝트 생성하기


[File]-[New]를 눌러 [Help Project]를 선택한 후 [OK]를 누른다. 파일 저장 대화상자가 뜨면 적당한 경로에 프로젝트 파일 이름을 지정한 후 [저장(S)] 버튼을 누른다. 이 때, 확장자는 .hpj이다. 주의할 것은, 경로명에 한글이 들어갈 경우 hlp 파일이 제대로 생성되지 않을 수 있다는 것이다. 경로에 한글이 들어가지 않도록 주의해야 한다.

예) C:\프로젝트\project.hpj (X) -> C:\project\project.hpj (O)

 

프로젝트에 RTF 문서 추가하기


프로젝트 파일이 생성되며 화면이 아래와 같이 변한다. [Options...] 버튼을 누른다. 이 도움말 파일의 이름이나 내용 등을 적을 수 있는 부분이다.

'Help title:'에는 이 도움말 파일의 제목을 적는다. 'Copyright Information'에는 저작권 관련 문구를 적어넣을 수 있다. 'Display this text in the Version dialog box:'에는 버전 정보 대화상자에 보여줄 문구를 지정하고, 'If users paste or print Help text, display:'에는 사용자가 도움말의 일부를 복사/붙여넣기하거나 인쇄를 할 때 딸려오는 저작권 관련 문구를 적을 수 있다.

 

대화상자에 입력한 내용이 프로젝트 파일에 반영되었음을 확인할 수 있다.

 

이번에는 [Files...]를 누른다. 'Topic Files'이라는 대화상자는 이 도움말에 포함된 .rtf 파일들의 목록들을 보여주는 창인데, 아무것도 없으므로 [Add...]를 눌러 파일을 하나 추가한다.

 

프로젝트 컴파일


아래와 같이 Microsoft Word에서 작성했던 rtf 파일이 추가되었다. 우선 결과를 보기위해 우측 하단의 [Save and Compile] 버튼을 클릭한다.

아무 문제없이 .hlp 형식 도움말 파일이 생성완료 되었다면 hlp 파일의 경로가 뜨면서 생성 완료되었다는 메시지가 출력될 것이다.

 

아래와 같이 .hlp 도움말 파일이 생성되었음을 확인할 수 있다. 더블클릭하여 열었을 때, Microsoft Word에서 작성했던 .rtf 파일과 같은 내용이 보인다면 성공한 것이다.

 

Epilogue


그럼 이어서 다음 글에서는 rtf 파일에 이미지와 표를 넣어보도록 한다.

 

카테고리 “Microsoft Windows/Win32 도움말 연동”
more...
썸네일 이미지
[Xcode 오류 해결] 터미널에서 gcc로 컴파일되지 않을 경우
터미널에서 gcc로 컴파일되지 않을 경우 macOS Mojave(10.14.1)로 업데이트한 후 gcc로 컴파일을 시도하였으나 다음과 같은 오류가 뜨면서 컴파일이 되지 않는다. 이 오류는 macOS가 업데이트 되든가, Xcode가 업데이트 되든가, 아무튼 뭐 하나 업데이트 될 때마다 뜨는 것 같다. $ gcc test.c -otest xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun 1 단계 아래의 명령어를 입력한다. $ xcode-select --install 2 단계 "'xcode-s..
macOS/Xcode IDE
2018. 11. 18. 17:21

[Xcode 오류 해결] 터미널에서 gcc로 컴파일되지 않을 경우

macOS/Xcode IDE
2018. 11. 18. 17:21

터미널에서 gcc로 컴파일되지 않을 경우


macOS Mojave(10.14.1)로 업데이트한 후 gcc로 컴파일을 시도하였으나 다음과 같은 오류가 뜨면서 컴파일이 되지 않는다.

이 오류는 macOS가 업데이트 되든가, Xcode가 업데이트 되든가, 아무튼 뭐 하나 업데이트 될 때마다 뜨는 것 같다.

$ gcc test.c -otest
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

 

1 단계


아래의 명령어를 입력한다.

$ xcode-select --install

"xcode-select --install" 꼭 외워 두자.

 

2 단계


"'xcode-select' 명령어는 명령어 라인 개발자 도구가 필요합니다. 도구를 지금 설치하겠습니까?" 메시지가 뜨면 [설치] 버튼을 클릭한다.

전에도 이 창을 본 것 같다면, 기분 탓이겠지...

 

3 단계


"명령어 라인 도구 사용권 계약"에 [동의] 버튼을 클릭한다.

계약서에 [동의]한다.

 

4 단계


터미널 상에서 gcc 컴파일을 수행하기 위한 소프트웨어가 설치되고 있는 중이다.

여유롭게 기다리고
설치 완료

 

5 단계


명령어 라인 도구의 설치가 끝나면 다음과 같이 정상적으로 gcc 컴파일이 수행된다.

오류 해결

 

썸네일 이미지
[macOS] macOS에서 유니코드로 문자 입력하기
macOS에서 유니코드로 문자 입력하기 Microsoft Windows에서는 유니코드로 문자를 입력할 때 '알트 입력법'을 사용한다. 예를 들어, 한글 '가'의 유니코드는 U+AC00(십진법으로 44,032)이므로, [Alt]를 누른 상태에서 숫자패드(일반적인 문자 키보드에 있는 숫자 키가 아니라, NumLock이 있는 숫자 키패드 영역에서 [0]-[9]의 글쇠)를 이용하여 44032를 입력하면 된다. 즉, Alt + 4, 4, 0, 3, 2 = '가'이다. 다음의 절차대로 유니코드 입력기를 추가하면, macOS에서도 이와 같은 유니코드 입력이 가능하다. 1 단계 먼저 사과 메뉴 [] - 시스템 환경설정System Preferences...을 클릭한다. 그리고 [키보드] 항목을 클릭한다. 2 단계 키보..
macOS/macOS 활용
2018. 11. 6. 21:06

[macOS] macOS에서 유니코드로 문자 입력하기

macOS/macOS 활용
2018. 11. 6. 21:06

macOS에서 유니코드로 문자 입력하기


Microsoft Windows에서는 유니코드로 문자를 입력할 때 '알트 입력법'을 사용한다. 예를 들어, 한글 '가'의 유니코드는 U+AC00(십진법으로 44,032)이므로, [Alt]를 누른 상태에서 숫자패드(일반적인 문자 키보드에 있는 숫자 키가 아니라, NumLock이 있는 숫자 키패드 영역에서 [0]-[9]의 글쇠)를 이용하여 44032를 입력하면 된다. 즉, Alt + 4, 4, 0, 3, 2 = '가'이다. 다음의 절차대로 유니코드 입력기를 추가하면, macOS에서도 이와 같은 유니코드 입력이 가능하다.

1 단계


먼저 사과 메뉴 [] - 시스템 환경설정System Preferences...을 클릭한다. 그리고 [키보드] 항목을 클릭한다.

System Preferences... 에서 Keyboard 클릭

 

2 단계


키보드 설정 화면에서 [입력 소스Input Sources] 탭을 클릭하고 [+] 버튼을 클릭한다.

Keyboard 화면 하단에서 더하기([+]) 버튼을 클릭한다.

 

3 단계


입력 언어 중 "기타Others"를 클릭하면 "유니코드 Hex 입력Unicode Hex Input"가 있다. 이를 선택하고 [추가Add] 버튼을 클릭한다.

추가할 키보드 목록에서 '기타'에 있는 'Unicode Hex Input'을 선택한다.

 

4 단계


다음과 같이 유니코드 Hex를 입력할 수 있도록 키보드가 추가되었다. 즉, 윈도우의 알트 입력법은 십진수를 기본으로 하는 반면, macOS는 16진법 그대로 입력이 가능하다.

키보드가 추가된 것을 확인한다.

 

5 단계


다음과 같이 키보드를 "유니코드 Hex 입력"으로 선택하면 유니코드로 문자를 직접 입력이 가능하다. 예를 들어, '가'의 유니코드는 U+AC00이라 했으므로 이를 입력하고자 하면 Option[⌥]를 누른 상태에서 순서대로 [A], [C], [0], [0]을 입력하면 된다. 즉, ⌥ + A, C, 0, 0 = '가'이다.

작업 표시줄에서 키보드(Unicode Hex Input)를 선택할 수 있다.

 

[단막 C++ 문법] const 위치에 따른 구문의 의미
const 위치에 따른 구문의 의미 네이버 지식iN에 이런 질문이 올라와서 이에 답변을 달았던 적이 있다. 예제보니까 parameter에 void foo(int* const* bar) 이렇게 있더라고요;; 이게 definition으로서 가능해요? 만일 가능하다면 도대체 이렇게 정의하는 목적이 뭔지;; 그리고 만일 이게 된다면 const* int* bar도 되나요?? 답변 부탁드리겠습니다 ㅠ- [네이버 지식iN] C++ int*const* 변수이름 은 도대체 뭐죠?? 본디 상수 특성을 지정하는 const 키워드는 그 놓인 위치에 따라 약간의 미묘한 의미 차이를 갖는다. 본 포스팅에서는 const 키워드가 들어간 구문의 정확한 의미를 정리해 보고자 한다. const의 선언 위치 const는 선언 문장 내 여..
Language/C & C++
2018. 11. 1. 12:06

[단막 C++ 문법] const 위치에 따른 구문의 의미

Language/C & C++
2018. 11. 1. 12:06

const 위치에 따른 구문의 의미


네이버 지식iN에 이런 질문이 올라와서 이에 답변을 달았던 적이 있다.

예제보니까 parameter에
void foo(int* const* bar)
이렇게 있더라고요;; 이게 definition으로서 가능해요? 만일 가능하다면 도대체 이렇게 정의하는 목적이 뭔지;;
그리고 만일 이게 된다면 const* int* bar도 되나요?? 답변 부탁드리겠습니다 ㅠ

- [네이버 지식iN] C++ int*const* 변수이름 은 도대체 뭐죠??

본디 상수 특성을 지정하는 const 키워드는 그 놓인 위치에 따라 약간의 미묘한 의미 차이를 갖는다. 본 포스팅에서는 const 키워드가 들어간 구문의 정확한 의미를 정리해 보고자 한다.

const의 선언 위치


const는 선언 문장 내 여러 곳에 놓일 수 있다. 그 때문에 의미가 혼동되고 읽기 불편할 수도 있다.

먼저 변수를 선언할 때에는 다음과 같이 const가 올 수 있다.

[const] 자료형 [const] [포인터] [const] 변수명;

 

함수를 선언할 때에는 다음과 같이 const가 올 수 있다.

[const] 자료형 [const] [포인터] 함수명(매개변수…) [const] { 함수본문 }

 

const 키워드가 어느 곳에 붙든 결국 원칙은 이것이다.

const가 걸리는 위치에서는 값 변경이 안 된다.

그렇다면 값 변경이 안 되는 경우(어디서 값 변경이 안 되는가?)를 찾는 것이 관건이다. 질문 원문에서 소개 된 3가지 경우를 예로 들어보면,

  1. const int ** foo;
  2. int * const * foo;
  3. int ** const foo;

이 3가지의 자료형이 있다. const가 붙는 위치가 조금씩 다름을 알 수 있는데 이 차이를 구분할 수 있다면 C의 고수이다.

위의 3가지 형식을 괄호로 쳐 본다면 다음과 같이 묶을 수 있다.

  1. (const int) ** a;
  2. (int * const) * a;
  3. (int **) const a;

 

'const 자료형 **'의 해설


1번은 const int 형에 대한 이중 포인터이다. 즉 int형 상수에 대한 이중 포인터라는 뜻이다. 보다 쉽게 나타낸다면 이런 과정으로 만들어지는 타입이다.

{
const int a = 10;
const int * b = &x; 
const int ** c = &y;
}

 

위와 같이 &b의 자료형이 const int ** 형이라 보면 된다. 알맹이 값인 a = 10이라는 값이 상수처리 되는 것이다.

반복하면,

{
  c : const int ** 형 (값 변경 O)
 *c : const int * 형 (값 변경 O)
**c : const int 형 (값 변경 X)
}

이므로,

int main(int argc, char * argv[]) {
    const int a = 10;
    const int * b = &a;
    const int ** c = &b; // 이게 const int ** 형식임.
    
      c = 0x00000000; // 대입시 에러 없음
     *c = 0x00000000; // 대입시 에러 없음
    **c = 5; // 여기서 에러.
    
    return 0;
}

 

'자료형 * const *'의 해설


2번은 int * 형이 갖는 주소 값을 상수로 다룬다는 뜻이다. 즉 int *형 상수에 대한 포인터라는 뜻이다. 보다 쉽게 나타낸다면 이런 과정을 통해 만들어지는 타입이다.

{
int a = 10;
int * const b = &a;
int * const * c = &b;
}

 

위와 같이 &b의 자료형이 int * const * 형이라 보면 된다. 여기서 알맹이 값인 a = 10은 수정이 자유로우나, 이것이 위치한 주소(a의 주소)를 갖고 있는 b가 상수처리 되는 것이다.

반복하면,

{
  c : int * const * 형 (값 변경 O)
 *c : int * const 형 (값 변경 X)
**c : int 형 (값 변경 O)
}

이므로,

int main(int argc, char * argv[]) {
    int a = 10;
    int * const b = &a; // 여기서 &b가 100% 완벽한 int * const * 형을 갖게 된다.
    int * const * c = &b; // 이게 int * const * 형이다.
    
      c = 0x00000000; // 대입시 에러 없음
     *c = 0x00000000; // 여기서 에러.
    **c = 5; // 대입시 에러 없음
    
    return 0;
}

 

'자료형 ** const'의 해설


3번은 int ** 타입 자체가 상수라는 뜻이다, 즉 이런 과정을 통해 만들어지는 타입이다.

{
int a = 10;
int * b = &a;
int ** const c = &b;
}

 

위와 같이 &b의 자료형을 상수로 처리하는 것이 int ** const 형이라 보면 된다.

{
  c : int ** const 형 (값 변경 X)
 *a : int *  형 (값 변경 O)
**a : int 형 (값 변경 O)
}

이므로,

int main(int argc, char * argv[]) {
    int a = 10;
    int * b = &a;
    int ** const c = &b;
    
      c = 0x00000000;// 여기서 에러.
     *c = 0x00000000; // 대입시 에러 없음
    **c = 5; // 대입시 에러 없음
    
    return 0;
}

 

마무리


지식 iN에도 올렸지만, 다시 한번 표로 정리하면 아래와 같이 요약 가능하다.

선언된 형식const int ** aint * const * aint ** const a
a의 형식const int ** 형 (값 변경 O)int * const * 형 (값 변경 O)int ** const 형 (값 변경 X)
*a의 형식const int * 형 (값 변경 O)int * const 형 (값 변경 X)int * 형 (값 변경 O)
**a의 형식const int 형 (값 변경 X)int 형 (값 변경 O)int 형 (값 변경 O)

 

덧 1. 문자열 상수와 const


strcpy 같은 함수를 보면 두 번째 인수가 const char * 형으로 되어 있을 것이다. 풀이해 보면, 그 문자열의 주소는 경우에 따라 가변적이지만 문자열이 갖는 자체의 내용만큼은 변함이 없다. 이런 뜻이다.

이를 테스트해보자.

void test(const char * str) {
    str = "이건 뭥미?"; // 대입 가능
}

str의 주소가 가리키는 문자열이 매개변수를 통해 넘어온 문자열이 아니라 전혀 새로운 문자열로 대치가 가능하다. 주소 자체에는 상수성이 없기 때문이다.

 

void test(const char * const str) {
    str = "이건 뭥미?"; // 대입 불가
}

문자열의 내용 자체가 불변인 것은 위와 같다. 또한 문자열을 가리키는 주소 또한 상수성을 갖고 있으므로 전혀 다른 문자열로 대치하는 것 또한 불가하다.

 

void test(char * str) {
    str = "ABCD"; // 대입 가능
    str[0] = 'A'; // 대입 가능
}

문자열의 내용과 문자열이 가리키는 주소 모두 상수성이 없다. 자유롭게 대치 및 수정 가능하다.

 

void test(const char * str) {
    str = "ABCD"; // 대입 가능
    str[0] = 'A'; // 대입 불가
}

문자열이 가리키는 주소 자체는 상수성이 없으므로 전혀 다른 문자열로 대치가 가능하다. 그러나 문자열의 내용에 대해서는 상수성이 있으므로 const char *로 선언된 문자열은 일부 내용의 수정이 불가하다.

 

덧 2. 멤버 함수와 const


C 언어에서 사용되는 const는 이 정도에서 끝나지만 C++로 넘어올 경우 하나가 더 있다. 멤버 함수의 scope에 붙이는 const 키워드이다.

class Integer {
    private:
        int value;
    public:
        int getInteger() const;
        void setInteger(int value);
}

int Integer::getInteger() const {
    return this->value;
}

void Integer::setInteger(int value) {
    this->value = value;
}

 

위와 같이 멤버 함수의 scope에도 상수성을 부여할 수 있다. 이것의 의미는...

이 함수는 멤버 변수의 값을 읽을 수는 있어도 수정할 수는 없다.

이다. 만일,

int Integer::getInteger() const {
    this->value = -1; // 오류 발생
    return this->value;
}

위와 같은 코드를 실행한다면 const가 부여된 scope 내에서 멤버 변수의 수정을 시도하므로 오류가 발생할 것이다. 또한,

int Integer::getInteger() const {
    this->setInteger(-1); // 오류 발생
    return this->value;
}

또한 위와 같이 scope에 const 속성이 없는 다른 함수를 호출하는 것도 오류가 발생한다. 상수 함수에서 호출 가능한 멤버함수는 같은 상수 함수 뿐이다. 반대로 scope에 const가 없는 함수는 상수 함수이든 비 상수 함수이든 호출이 가능하다. 이렇게 선언하는 이유는 객체의 상수성 때문이다.

{
    Integer i1;
    const Integer i2;

    i1.setInteger(-1); // 가능
    i1.getInteger(); // 가능
    i2.setInteger(-1); // 불가
    i2.getInteger(); // 가능
}

객체 i1은 상수성이 없고, 객체 i2는 상수성이 있다. 상수성이 있는 객체는 멤버 변수의 수정이 불가능하므로 scope에 const가 명시된 멤버 함수만이 호출 가능하다. 따라서 i2.setInteger(-1);와 같은 호출은 불가능하다.

 

카테고리 “Language/C & C++”
more...
썸네일 이미지
ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
ASP.NET 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - ..
Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 19:47

ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 19:47

ASP.NET 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part II. 세션을 사용한 로그인, 로그아웃 (ASP.NET/C#)


본 게시물에서는 ASP.NET 소스 코드로 세션에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 서버에 로그인 정보를 보관하고 이 정보에 접근할 수 있는 식별 번호를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 통해 세션 번호를 서버에 전달하고, 서버는 해당 번호의 세션이 보유한 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.aspx - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<%@ Page Language="C#" CodePage="65001" %>
<%
	Response.Charset="UTF-8";
	Response.ContentType="text/html;charset=UTF-8";
	Session.CodePage=65001;
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<%--------------------------------------------------------------------------
	   웹 페이지 본문 영역
	  ------------------------------------------------------------------------%>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.aspx" method="post">
				<label for="trialUsername">사용자 이름 : </label><input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label><input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.aspx 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.aspx로 전달할 것이다.

step2.aspx - 사용자 인증


이 페이지는 step1.aspx에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 세션 변수에 각각 아이디와 암호를 보관하고, 해당 세션의 식별번호를 쿠키를 통해 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<%@ Page Language="C#" CodePage="65001" %>
<%
	Response.Charset="UTF-8";
	Response.ContentType="text/html;charset=UTF-8";
	Session.CodePage=65001;
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style>a { color: #0000FF; }</style>
		<%--------------------------------------------------------------------
		   사용자 인증 로직
		   이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 true, 아니면 false
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 true를 반환하고 승인 거부 시 false를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%--------------------------------------------------------------------
		   웹 페이지 헤더 영역
		   이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string trialUsername = null;
				string trialPassword = null;

				this.authorizeStatus = false;

				// POST 방식으로 전달된 데이터 중 trialUsername이라는 데이터가 있는지 확인
				if (Request.Form["trialUsername"] != null)
				{
					// trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인 
					if (Request.Form["trialPassword"] != null)
					{
						// POST 데이터에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
						trialUsername = Request.Form["trialUsername"];
						trialPassword = Request.Form["trialPassword"];

						// trialUsername과 trialPassword가 모두 수신되면,
						// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
						this.authorizeStatus = authorizeMembership
						(
							trialUsername,
							trialPassword
						);
					}
				}

				// 로그인 요청이 승인되었다면
				if (this.authorizeStatus)
				{
					// membershipUsername이라 이름붙인 세션 변수에
					// 사용자 이름을 기록한다.
					Session["membershipUsername"] = trialUsername;

					// membershipPassword이라 이름붙인 세션 변수에
					// 사용자 암호를 기록한다.
					Session["membershipPassword"] = trialPassword;

					// 세션의 유효 기간은 12시간으로 한다.
					Session.Timeout = 12 * 60;
				}

				return;
			}
		</script>
	</head>
	<%--------------------------------------------------------------------------
	   웹 페이지 본문 영역
	  ------------------------------------------------------------------------%>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<%-- 로그인 승인 되었다면... --%>
			<p>로그인에 성공했습니다.</p>
			<p><a href="./step3.aspx">회원 페이지</a></p>
			<% } else { %>
			<%-- 로그인 거부 되었다면... --%>
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.aspx">로그인 화면</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.aspx">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.aspx 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.aspx 소스 코드의 실행 화면 (로그인 실패)

ASP의 경우 세션 정보들은 객체의 형태로 메모리에 보관된다.

step3.aspx - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 세션 식별 번호를 전달받는다. 서버의 특정 위치에서 해당 번호를 갖는 세션을 읽어온 후, 로그인 상태임이 확인되면 회원 전용 페이지를 출력한다. 그렇지 않다면 비회원용 페이지를 출력한다.

<%@ Page Language="C#" CodePage="65001" %>
<%
	Response.Charset="UTF-8";
	Response.ContentType="text/html;charset=UTF-8";
	Session.CodePage=65001;
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
		<style>a { color: #0000FF; }</style>
		<%--------------------------------------------------------------------
		   사용자 인증 로직
		   이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 true, 아니면 false
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%--------------------------------------------------------------------
		   웹 페이지 헤더 영역
		   클라이언트의 쿠키로부터 전송된 사용자 이름 및 암호를 읽어온다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string membershipUsername = null;
				string membershipPassword = null;

				this.authorizeStatus = false;

				// 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
				if (Session["membershipUsername"] != null)
				{
					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Session["membershipPassword"] != null)
					{
						// 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
						membershipUsername = Session["membershipUsername"].ToString();
						membershipPassword = Session["membershipPassword"].ToString();

						// membershipUsername과 membershipPassword가 모두 수신되면,
						// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
						this.authorizeStatus = authorizeMembership
						(
							membershipUsername,
							membershipPassword
						);
					}
				}

				// 로그인 요청이 승인되었다면
				if (this.authorizeStatus)
				{
					// membershipUsername이라 이름붙인 세션 변수에
					// 사용자 이름을 기록한다.
					Session["membershipUsername"] = membershipUsername;

					// membershipPassword이라 이름붙인 세션 변수에
					// 사용자 암호를 기록한다.
					Session["membershipPassword"] = membershipPassword;

					// 세션의 유효기간은 12시간으로 한다.
					Session.Timeout = 12 * 60;
				}

				return;
			}
		</script>
	</head>
	<%--------------------------------------------------------------------------
	   웹 페이지 본문 영역
	  ------------------------------------------------------------------------%>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<%-- 로그인 승인 되었다면... --%>
			<p>회원 전용 페이지</p>
			<p>환영합니다. <%=Session["membershipUsername"].ToString()%> 님.</p>
			<p>쿠키 문자열 :</p>
			<pre><code><%=Request.ServerVariables["HTTP_COOKIE"]%></code></pre>
			<p><a href="./step4.aspx">로그아웃</a></p>
			<% } else { %>
			<%-- 로그인 거부 되었다면... --%>
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.aspx">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.aspx">1 단계(로그인)</a> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 4] step3.aspx 소스 코드의 실행 화면 (로그인 성공)
[그림 5] step3.aspx 소스 코드의 실행 화면 (로그인 실패)

step4.aspx - 로그아웃 화면


로그인 상태임이 확인되면 서버의 세션을 삭제하고 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<%@ Page Language="C#" CodePage="65001" %>
<%
	Response.Charset="UTF-8";
	Response.ContentType="text/html;charset=UTF-8";
	Session.CodePage=65001;
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>4 단계 : 로그아웃</title>
		<style>a { color: #0000FF; }</style>
		<%--------------------------------------------------------------------
		   사용자 인증 로직
		   이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 True, 아니면 False
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%--------------------------------------------------------------------
		   웹 페이지 헤더 영역
		   클라이언트의 쿠키로부터 전송된 사용자 이름 및 암호를 읽어온다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string membershipUsername = null;
				string membershipPassword = null;

				this.authorizeStatus = false;

				// 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
				if (Session["membershipUsername"] != null)
				{
					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Session["membershipPassword"] != null)
					{
						// 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
						membershipUsername = Session["membershipUsername"].ToString();
						membershipPassword = Session["membershipPassword"].ToString();

						// membershipUsername과 membershipPassword가 모두 수신되면,
						// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
						this.authorizeStatus = authorizeMembership
						(
							membershipUsername,
							membershipPassword
						);
					}
				}

				// 로그아웃은 로그인 여부와 무관하게 시행된다.
				// 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간 이전으로 설정한다.

				// membershipUsername이라 이름붙인 세션 변수에
				// 사용자 이름을 기록한다.
				Session["membershipUsername"] = "<undefined>";

				// membershipPassword이라 이름붙인 세션 변수에
				// 사용자 암호를 기록한다.
				Session["membershipPassword"] = "<undefined>";

				// 세션을 삭제한다.
				Session.Abandon();

				return;
			}
		</script>
	</head>
	<%--------------------------------------------------------------------------
	   웹 페이지 본문 영역
	  ------------------------------------------------------------------------%>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<%-- 로그인 승인 되었다면... --%>
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.aspx">로그인</a></p>
			<% } else { %>
			<%-- 로그인 거부 되었다면... --%>
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.aspx">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.aspx">1 단계(로그인)</a> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
[그림 6] step4.aspx 소스 코드의 실행 화면 (로그아웃 성공)
[그림 7] step4.asp 소스 코드의 실행 화면 (이미 로그아웃된 상태)

step1.aspx - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.aspx을 살펴보면, 세션으로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.aspx에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<%@ Page Language="C#" CodePage="65001" %>
<%
	Response.Charset="UTF-8";
	Response.ContentType="text/html;charset=UTF-8";
	Session.CodePage=65001;
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
		<%--------------------------------------------------------------------
		   사용자 인증 로직
		   이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 true, 아니면 false
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%--------------------------------------------------------------------
		   웹 페이지 헤더 영역
		   이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.
		  --------------------------------------------------------------------%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string membershipUsername = null;
				string membershipPassword = null;

				this.authorizeStatus = false;

				// 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
				if (Session["membershipUsername"] != null)
				{
					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Session["membershipPassword"] != null)
					{
						// 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
						membershipUsername = Session["membershipUsername"].ToString();
						membershipPassword = Session["membershipPassword"].ToString();

						// membershipUsername과 membershipPassword가 모두 수신되면,
						// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
						this.authorizeStatus = authorizeMembership
						(
							membershipUsername,
							membershipPassword
						);
					}
				}

				// 로그인 요청이 승인되었다면
				if (this.authorizeStatus)
				{
					// membershipUsername이라 이름붙인 세션 변수에 
					// 사용자 이름을 기록한다.
					Session["membershipUsername"] = membershipUsername;

					// membershipPassword이라 이름붙인 세션 변수에
					// 사용자 암호를 기록한다.
					Session["membershipPassword"] = membershipPassword;

					// 세션의 유효기간은 12시간으로 설정한다.
					Session.Timeout = 12 * 60;
				}

				return;
			}
		</script>
	</head>
	<%--------------------------------------------------------------------------
	   웹 페이지 본문 영역
	  ------------------------------------------------------------------------%>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<%-- 로그인 승인 되었다면... --%>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="step3.aspx">회원 페이지</a></p>
			<% } else { %>
			<%-- 로그인 거부 되었다면... --%>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.aspx" method="post">
				<label for="trialUsername">사용자 이름 : </label><input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label><input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 8] 로그인이 유효한 상태에서 접속하였을 때, step1.aspx 소스 코드의 출력 결과
카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
썸네일 이미지
ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
ASP.NET 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - ..
Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 19:40

ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)

Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 19:40

ASP.NET 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part I. 쿠키를 사용한 로그인, 로그아웃 (ASP.NET/C#)


본 게시물에서는 ASP.NET 소스 코드로 세션에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 서버에 로그인 정보를 보관하고 이 정보에 접근할 수 있는 식별 번호를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 통해 세션 번호를 서버에 전달하고, 서버는 해당 번호의 세션이 보유한 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.aspx - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<%@ Page Language="C#" CodePage="65001" %>
<% Response.Charset="utf-8"; %>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<%-- 웹 페이지 본문 영역 --%>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.aspx" method="post">
				<label for="trialUsername">사용자 이름 : </label><input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label><input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.aspx 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.aspx로 전달할 것이다.

step2.aspx - 사용자 인증


이 페이지는 step1.aspx에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 세션 변수에 각각 아이디와 암호를 보관하고, 해당 세션의 식별번호를 쿠키를 통해 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<%@ Page Language="C#" CodePage="65001" %>
<% Response.Charset="utf-8"; %>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style>a { color: #0000FF; }</style>
		<%-- 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다. --%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 True, 아니면 False
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%-- 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다. --%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string trialUsername = null;
				string trialPassword = null;
				HttpCookie objectUsername = null;
				HttpCookie objectPassword = null;

				this.authorizeStatus = false;

				// POST 방식으로 넘어온 데이터 중 membershipUsername이라는 데이터가 있는지 확인
				if (Request.Form["trialUsername"] != null)
				{
					trialUsername = Request.Form["trialUsername"];

					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Request.Form["trialPassword"] != null)
					{
						trialPassword = Request.Form["trialPassword"];

						// trialUsername과 trialPassword가 모두 수신되면,
						// 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다
						this.authorizeStatus = authorizeMembership(trialUsername, trialPassword);
					}
				}

				// 로그인 요청이 승인되었다면
				if (this.authorizeStatus)
				{
					// membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에
					// 사용자 이름을 적어 클라이언트로 전송한다.
					objectUsername = new HttpCookie("membershipUsername");
					objectUsername.Value = trialUsername;
					objectUsername.Expires = DateTime.Now.AddHours(12.0);

					// membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에
					// 사용자 암호를 적어 클라이언트로 전송한다.
					objectPassword = new HttpCookie("membershipPassword");
					objectPassword.Value = trialPassword;
					objectPassword.Expires = DateTime.Now.AddHours(12.0);

					// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
					Response.Cookies.Add(objectUsername);
					Response.Cookies.Add(objectPassword);
				}

				return;
			}
		</script>
	</head>
	<%-- 웹 페이지 본문 영역 --%>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<!-- 로그인 승인 되었다면... -->
			<p>로그인에 성공했습니다.</p>
			<p><a href="./step3.aspx">회원 페이지</a></p>
			<% } else { %>
			<!-- 로그인 거부 되었다면... -->
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.aspx">로그인 화면</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.aspx">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.aspx 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.aspx 소스 코드의 실행 화면 (로그인 실패)

ASP.NET의 경우 세션 정보들은 객체의 형태로 메모리에 보관된다.

step3.aspx - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 아이디와 암호를 전달받는다. 로그인 상태임이 확인되면 회원 전용 페이지를 출력하고, 그렇지 않다면 비회원용 페이지를 출력한다.

<%@ Page Language="C#" CodePage="65001" %>
<% Response.Charset="utf-8"; %>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style>a { color: #0000FF; }</style>
		<%-- 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다. --%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 True, 아니면 False
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%-- 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다. --%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string membershipUsername = null;
				string membershipPassword = null;
				HttpCookie objectUsername = null;
				HttpCookie objectPassword = null;

				this.authorizeStatus = false;

				// POST 방식으로 넘어온 데이터 중 membershipUsername이라는 데이터가 있는지 확인
				if (Request.Cookies["membershipUsername"] != null)
				{
					membershipUsername = Request.Cookies["membershipUsername"].Value;

					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Request.Cookies["membershipPassword"] != null)
					{
						membershipPassword = Request.Cookies["membershipPassword"].Value;

						// trialUsername과 trialPassword가 모두 수신되면,
						// 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다
						this.authorizeStatus = authorizeMembership(membershipUsername, membershipPassword);
					}
				}

				// 로그인 요청이 승인되었다면
				if (this.authorizeStatus)
				{
					// membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에
					// 사용자 이름을 적어 클라이언트로 전송한다.
					objectUsername = new HttpCookie("membershipUsername");
					objectUsername.Value = membershipUsername;
					objectUsername.Expires = DateTime.Now.AddHours(12.0);

					// membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에
					// 사용자 암호를 적어 클라이언트로 전송한다.
					objectPassword = new HttpCookie("membershipPassword");
					objectPassword.Value = membershipPassword;
					objectPassword.Expires = DateTime.Now.AddHours(12.0);

					// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
					Response.Cookies.Add(objectUsername);
					Response.Cookies.Add(objectPassword);
				}

				return;
			}
		</script>
	</head>
	<%-- 웹 페이지 본문 영역 --%>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<!-- 로그인 승인 되었다면... -->
			<p>회원 전용 페이지</p>
			<p>환영합니다. <%=Request.Cookies["membershipUsername"].Value%> 님.</p>
			<p>쿠키 문자열 :</p>
			<pre><code><%=Request.ServerVariables["HTTP_COOKIE"]%></code></pre>
			<p><a href="./step4.aspx">로그아웃</a></p>
			<% } else { %>
			<!-- 로그인 거부 되었다면... -->
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.aspx">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.aspx">1 단계(로그인)</a> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 4] step3.aspx 소스 코드의 실행 화면 (로그인 성공)
[그림 5] step3.aspx 소스 코드의 실행 화면 (로그인 실패)

step4.aspx - 로그아웃 화면


로그인 상태임이 확인되면 서버의 세션을 삭제하고 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<%@ Page Language="C#" CodePage="65001" %>
<% Response.Charset="utf-8"; %>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style>a { color: #0000FF; }</style>
		<%-- 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다. --%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 True, 아니면 False
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%-- 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다. --%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string membershipUsername = null;
				string membershipPassword = null;
				HttpCookie objectUsername = null;
				HttpCookie objectPassword = null;

				this.authorizeStatus = false;

				// POST 방식으로 넘어온 데이터 중 membershipUsername이라는 데이터가 있는지 확인
				if (Request.Cookies["membershipUsername"] != null)
				{
					membershipUsername = Request.Cookies["membershipUsername"].Value;

					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Request.Cookies["membershipPassword"] != null)
					{
						membershipPassword = Request.Cookies["membershipPassword"].Value;

						// trialUsername과 trialPassword가 모두 수신되면,
						// 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다
						this.authorizeStatus = authorizeMembership(membershipUsername, membershipPassword);
					}
				}

				// 쿠키변수의 제거는 로그인 여부와 무관하게 시행된다.
				// 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간 이전으로 설정한다.

				// membershipUsername이라 이름붙인 유효기간 만료된 쿠키변수에 
				// 사용자 이름을 적어 클라이언트로 전송한다.
				objectUsername = new HttpCookie("membershipUsername");
				objectUsername.Value = "<undefined>";
				objectUsername.Expires = DateTime.Now.AddHours(-12.0);

				// membershipPassword이라 이름붙인 유효기간 만료된 쿠키변수에 
				// 사용자 이름을 적어 클라이언트로 전송한다.
				objectPassword = new HttpCookie("membershipPassword");
				objectPassword.Value = "<undefined>";
				objectPassword.Expires = DateTime.Now.AddHours(-12.0);

				Response.Cookies.Add(objectUsername);
				Response.Cookies.Add(objectPassword);

				return;
			}
		</script>
	</head>
	<%-- 웹 페이지 본문 영역 --%>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<!-- 로그인 된 상태였다면... -->
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.aspx">로그인</a></p>
			<% } else { %>
			<!-- 로그인 안 된 상태였다면... -->
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.aspx">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.aspx">1 단계(로그인)</a> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
[그림 6] step4.asp 소스 코드의 실행 화면 (로그아웃 성공)
[그림 7] step4.asp 소스 코드의 실행 화면 (이미 로그아웃된 상태)

step1.aspx - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.aspx을 살펴보면, 세션으로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.aspx에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<%@ Page Language="C#" CodePage="65001" %>
<% Response.Charset="utf-8"; %>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
		<style>a { color: #0000FF; }</style>
		<%-- 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다. --%>
		<script language="C#" runat="server">
			// 아래 이름의 사용자면 로그인 승인 함.
			private const string authorizedUsername = "codingCat";
			// 아래의 암호를 입력하면 로그인 승인 함.
			private const string authorizedPassword = "qwerty123456!";

			// 로그인 승인 시 True, 아니면 False
			private bool authorizeStatus = false;

			// authorizeMembership(trialUsername, trialPassword)
			// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
			// trialUsername : 로그인을 시도하는 사용자 이름
			// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
			// 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
			private static bool authorizeMembership(string trialUsername, string trialPassword)
			{
				// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
				if (string.Equals(trialUsername, authorizedUsername))
				{
					// 이름이 일치하면, 암호가 같은지 검사
					if (string.Equals(trialPassword, authorizedPassword))
					{
						// 이름과 암호가 모두 일치하면 로그인 승인
						return true;
					}
				}
				// 그렇지 않을 경우 로그인 거부
				return false;
			}
		</script>
		<%-- 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다. --%>
		<script language="C#" runat="server">
			private void Page_Load(object sender, EventArgs e)
			{
				string membershipUsername = null;
				string membershipPassword = null;
				HttpCookie objectUsername = null;
				HttpCookie objectPassword = null;

				this.authorizeStatus = false;

				// POST 방식으로 넘어온 데이터 중 membershipUsername이라는 데이터가 있는지 확인
				if (Request.Cookies["membershipUsername"] != null)
				{
					membershipUsername = Request.Cookies["membershipUsername"].Value;
					// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
					if (Request.Cookies["membershipPassword"] != null)
					{
						membershipPassword = Request.Cookies["membershipPassword"].Value;
						// trialUsername과 trialPassword가 모두 수신되면,
						// 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다
						this.authorizeStatus = authorizeMembership(membershipUsername, membershipPassword);
					}
				}

				// 로그인 요청이 승인되었다면
				if (this.authorizeStatus)
				{
					// membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에
					// 사용자 이름을 적어 클라이언트로 전송한다.
					objectUsername = new HttpCookie("membershipUsername");
					objectUsername.Value = membershipUsername;
					objectUsername.Expires = DateTime.Now.AddHours(12.0);

					// membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에
					// 사용자 암호를 적어 클라이언트로 전송한다.
					objectPassword = new HttpCookie("membershipPassword");
					objectPassword.Value = membershipPassword;
					objectPassword.Expires = DateTime.Now.AddHours(12.0);

					// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
					Response.Cookies.Add(objectUsername);
					Response.Cookies.Add(objectPassword);
				}

				return;
			}
		</script>
	</head>
	<%-- 웹 페이지 본문 영역 --%>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="step3.aspx">회원 페이지</a></p>
			<% } else { %>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.aspx" method="post">
				<label for="trialUsername">사용자 이름 : </label><input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label><input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.aspx">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.aspx">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.aspx">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 8] 로그인이 유효한 상태에서 접속하였을 때, step1.aspx 소스 코드의 출력 결과
카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
썸네일 이미지
ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
ASP 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 ..
Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 19:15

ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 19:15

ASP 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part II. 세션을 사용한 로그인, 로그아웃 (ASP/VBScript)


본 게시물에서는 ASP 소스 코드로 세션에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 서버에 로그인 정보를 보관하고 이 정보에 접근할 수 있는 식별 번호를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 통해 세션 번호를 서버에 전달하고, 서버는 해당 번호의 세션이 보유한 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.asp - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
	Session.CodePage="65001"
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.asp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.asp 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.asp로 전달할 것이다.

step2.asp - 사용자 인증


이 페이지는 step1.asp에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 세션 변수에 각각 아이디와 암호를 보관하고, 해당 세션의 식별번호를 쿠키를 통해 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
	Session.CodePage="65001"
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 헤더 영역
' 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

Dim trialUsername
Dim trialPassword

authorizeStatus = False

' POST 방식으로 전달된 데이터 중 trialUsername이라는 데이터가 있는지 확인
If Not IsNull(Request.Form("trialUsername")) Then
	trialUsername = Request.Form("trialUsername")
	' trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인
	If Not IsNull(Request.Form("trialPassword")) Then
		trialPassword = Request.Form("trialPassword")
		' trialUsername과 trialPassword가 모두 수신되면,
		' 앞서 정의된 authorizeMembership 함수로 로그인 요청한다.
		authorizeStatus = authorizeMembership(trialUsername, trialPassword)
	End If
End If

' 로그인 요청이 승인되었다면
If authorizeStatus = True Then
	' membershipUsername이라 이름붙인 세션 변수에
	' 사용자 이름을 기록한다.
	Session("membershipUsername") = trialUsername
	' membershipPassword이라 이름붙인 세션 변수에
	' 사용자 암호를 기록한다.
	Session("membershipPassword") = trialPassword
	' 세션의 유효기간을 12시간으로 설정한다. [단위: 분]
	Session.Timeout = 12 * 60
End If
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style>a { color: #0000FF; }</style>
	</head>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 승인 되었다면...' %>
			<p>로그인에 성공했습니다.</p>
			<p><a href="./step3.asp">회원 페이지</a></p>
			<% Else %>
			<% '로그인 거부 되었다면...' %>
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.asp">로그인 화면</a></p>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.asp">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.asp 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.asp 소스 코드의 실행 화면 (로그인 실패)

ASP의 경우 세션 정보들은 객체의 형태로 메모리에 보관된다.

step3.asp - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 세션 식별 번호를 전달받는다. 서버의 특정 위치에서 해당 번호를 갖는 세션을 읽어온 후, 로그인 상태임이 확인되면 회원 전용 페이지를 출력한다. 그렇지 않다면 비회원용 페이지를 출력한다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
	Session.CodePage="65001"
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 헤더 영역
' 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

Dim membershipUsername
Dim membershipPassword

authorizeStatus = False

' 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
If Not IsNull(Session("membershipUsername")) Then
	' membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	If Not IsNull(Session("membershipPassword")) Then
		' 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = Session("membershipUsername")
		membershipPassword = Session("membershipPassword")
		' trialUsername과 trialPassword가 모두 수신되면,
		' 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다
		authorizeStatus = authorizeMembership(membershipUsername, membershipPassword)
	End If
End If

' 로그인 요청이 승인되었다면
If authorizeStatus = True Then
	' membershipUsername이라 이름붙인 세션 변수에
	' 사용자 이름을 기록한다.
	Session("membershipUsername") = membershipUsername
	' membershipPassword이라 이름붙인 세션 변수에
	'' 사용자 암호를 기록한다.
	Session("membershipPassword") = membershipPassword
	' 세션의 유효기간을 12시간으로 설정한다. [단위: 분]
	Session.Timeout = 12 * 60
End If
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 승인 되었다면...' %>
			<p>회원 전용 페이지</p>
			<p>환영합니다. <%=membershipUsername%> 님.</p>
			<p>쿠키 문자열 :</p>
			<pre><code><%=Request.ServerVariables("HTTP_COOKIE")%></code></pre>
			<p><a href="./step4.asp">로그아웃</a></p>
			<% Else %>
			<% '로그인 거부 되었다면...' %>
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.asp">로그인</a></p>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.asp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 4] step3.asp 소스 코드의 실행 화면 (로그인 성공)
[그림 5] step3.asp 소스 코드의 실행 화면 (로그인 실패)

step4.asp - 로그아웃 화면


로그인 상태임이 확인되면 서버의 세션을 삭제하고 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
	Session.CodePage="65001"
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 헤더 영역
' 세션에 저장된 사용자 이름 및 암호를 읽어온다.

Dim membershipUsername
Dim membershipPassword

authorizeStatus = False


' 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
If Not IsNull(Session("membershipUsername")) Then
	' membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	If Not IsNull(Session("membershipPassword")) Then
		' 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = Session("membershipUsername")
		membershipPassword = Session("membershipPassword")
		' membershipUsername과 membershipPassword가 모두 수신되면,
		' 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership(membershipUsername, membershipPassword)
	End If
End If

' 로그아웃은 로그인 여부와 무관하게 수행된다.

' membershipUsername이라 이름붙인 세션 변수에
' 사용자 이름을 기록한다.
Session("membershipUsername") = "<undefined>"

' membershipPassword이라 이름붙인 세션 변수에
' 사용자 암호를 기록한다.
Session("membershipPassword") = "<undefined>"

' 서버에서 세션을 제거한다.
Session.Abandon()
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>4 단계 : 로그아웃</title>
		<style>a { color: #0000FF; }</style>
	</head>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 된 상태였다면...' %>
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.asp">로그인</a></p>
			<% Else %>
			<% '로그인 안 된 상태였다면...' %>
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.asp">로그인</a></p>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.asp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
[그림 6] step4.asp 소스 코드의 실행 화면 (로그아웃 성공)
[그림 7] step4.asp 소스 코드의 실행 화면 (이미 로그아웃된 상태)

step1.asp - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.asp을 살펴보면, 세션으로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.asp에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
	Session.CodePage="65001"
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 헤더 영역
' 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

Dim membershipUsername
Dim membershipPassword

authorizeStatus = False

' 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
If Not IsNull(Session("membershipUsername")) Then
	' membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	If Not IsNull(Session("membershipPassword")) Then
		' 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = Session("membershipUsername")
		membershipPassword = Session("membershipPassword")
		' trialUsername과 trialPassword가 모두 수신되면,
		' 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다
		authorizeStatus = authorizeMembership(membershipUsername, membershipPassword)
	End If
End If

' 로그인 요청이 승인되었다면
If authorizeStatus = True Then
	' membershipUsername이라 이름붙인 세션 변수에
	' 사용자 이름을 기록한다.
	Session("membershipUsername") = membershipUsername
	' membershipPassword이라 이름붙인 세션 변수에
	' 사용자 암호를 기록한다.
	Session("membershipPassword") = membershipPassword
	' 세션의 유효기간을 12시간으로 설정한다. [단위: 분]
	Session.Timeout = 12 * 60
End If

%>
<%
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 승인 되었다면...' %>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="step3.asp">회원 페이지</a></p>
			<% Else %>
			<% '로그인 거부 되었다면...' %>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.asp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 8] 로그인이 유효한 상태에서 접속하였을 때, step1.asp 소스 코드의 출력 결과
카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
썸네일 이미지
ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
ASP 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 ..
Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 18:31

ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)

Common Gateway Interface/ASP & ASP.NET
2018. 9. 25. 18:31

ASP 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part I. 쿠키를 사용한 로그인, 로그아웃 (ASP/VBScript)


본 게시물에서는 ASP 소스 코드로 세션에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 서버에 로그인 정보를 보관하고 이 정보에 접근할 수 있는 식별 번호를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 통해 세션 번호를 서버에 전달하고, 서버는 해당 번호의 세션이 보유한 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.asp - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
%>
<%
'###############################################################################
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.asp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.asp 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.asp로 전달할 것이다.

step2.asp - 사용자 인증


이 페이지는 step1.asp에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 세션 변수에 각각 아이디와 암호를 보관하고, 해당 세션의 식별번호를 쿠키를 통해 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
%>
<%
'###############################################################################
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
'###############################################################################
' 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

Dim trialUsername
Dim trialPassword

authorizeStatus = False

' POST 방식으로 넘어온 데이터 중 trialUsername이라는 데이터가 있는지 확인
If Not IsNull(Request.Form("trialUsername")) Then
	' trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인 
	If Not IsNull(Request.Form("trialPassword")) Then
		' POST 데이터에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		trialUsername = Request.Form("trialUsername")
		trialPassword = Request.Form("trialPassword")
		' trialUsername과 trialPassword가 모두 수신되면,
		' 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership(trialUsername, trialPassword)
	End If
End If

' 로그인 요청이 승인되었다면
If authorizeStatus = True Then
	' 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	' membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
	' 사용자 이름을 기록한다.
	Response.Cookies("membershipUsername") = trialUsername
	Response.Cookies("membershipUsername").Expires = DateAdd("h", 12, Now())
	Response.Cookies("membershipUsername").Path = "/"
	' membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
	' 사용자 암호를 기록한다.
	Response.Cookies("membershipPassword") = trialPassword
	Response.Cookies("membershipPassword").Expires = DateAdd("h", 12, Now())
	Response.Cookies("membershipPassword").Path = "/"
End If
%>
<%
'###############################################################################
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style>a { color: #0000FF; }</style>
	</head>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 승인 되었다면... %>
			<p>로그인에 성공했습니다.</p>
			<p><a href="./step3.asp">회원 페이지</a></p>
			<% Else %>
			<% '로그인 거부 되었다면... %>
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.asp">로그인 화면</a></p>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.asp">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.asp 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.asp 소스 코드의 실행 화면 (로그인 실패)

ASP의 경우 세션 정보들은 객체의 형태로 메모리에 보관된다.

step3.asp - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 아이디와 암호를 전달받는다. 로그인 상태임이 확인되면 회원 전용 페이지를 출력하고, 그렇지 않다면 비회원용 페이지를 출력한다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
%>
<%
'###############################################################################
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
'###############################################################################
' 웹 페이지 헤더 영역
' 쿠키에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

Dim trialUsername
Dim trialPassword

authorizeStatus = False

' 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
If Not IsNull(Request.Cookies("membershipUsername")) Then
	' membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	If Not IsNull(Request.Cookies("membershipPassword")) Then
		' 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		trialUsername = Request.Cookies("membershipUsername")
		trialPassword = Request.Cookies("membershipPassword")
		' membershipUsername과 membershipPassword가 모두 수신되면,
		' 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership(trialUsername, trialPassword)
	End If
End If

' 로그인 요청이 승인되었다면
If authorizeStatus = True Then
	' 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간으로 연장한다.
	' 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	' membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
	' 사용자 이름을 적어 클라이언트로 전송한다.
	Response.Cookies("membershipUsername") = trialUsername
	Response.Expires = DateAdd("h", 12, Now())
	' membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
	' 사용자 이름을 적어 클라이언트로 전송한다.
	Response.Cookies("membershipPassword") = trialPassword
	Response.Expires = DateAdd("h", 12, Now())
End If
%>
<%
'###############################################################################
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
		<style>a { color: #0000FF; }</style>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 승인 되었다면... %>
			<p>회원 전용 페이지</p>
			<p>환영합니다. <%=membershipUsername%> 님.</p>
			<p>쿠키 문자열 :</p>
			<pre><code><%=Request.ServerVariables("HTTP_COOKIE")%></code></pre>
			<p><a href="./step4.asp">로그아웃</a></p>
			<% Else %>
			<% '로그인 거부 되었다면... %>
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.asp">로그인</a></p>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.asp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 4] step3.asp 소스 코드의 실행 화면 (로그인 성공)
[그림 5] step3.asp 소스 코드의 실행 화면 (로그인 실패)

step4.asp - 로그아웃 화면


로그인 상태임이 확인되면 서버의 세션을 삭제하고 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
%>
<%
'###############################################################################
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
'###############################################################################
' 웹 페이지 헤더 영역
' 쿠키에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

Dim membershipUsername
Dim membershipPassword

authorizeStatus = False

' 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
If Not IsNull(Request.Cookies("membershipUsername")) Then
	' membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	If Not IsNull(Request.Cookies("membershipPassword")) Then
		' 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = Request.Cookies("membershipUsername")
		membershipPassword = Request.Cookies("membershipPassword")
		' membershipUsername과 membershipPassword가 모두 수신되면,
		' 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership(membershipUsername, membershipPassword)
	End If
End If

' 로그아웃은 로그인 여부와 무관하게 수행된다.
' 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간 이전으로 설정한다.
' 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함

' membershipUsername이라 이름붙인 유효기간 만료된 쿠키변수에 
' 사용자 이름을 적어 클라이언트로 전송한다.
Response.Cookies("membershipUsername") = "<undefined>"
Response.Cookies("membershipUsername").Expires = DateAdd("h", -12, Now())
Response.Cookies("membershipUsername").Path = "/"

' membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
' 사용자 이름을 적어 클라이언트로 전송한다.
Response.Cookies("membershipPassword") = "<undefined>"
Response.Cookies("membershipPassword").Expires = DateAdd("h", -12, Now())
Response.Cookies("membershipPassword").Path = "/"
%>
<%
'###############################################################################
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>4 단계 : 로그아웃</title>
		<style>a { color: #0000FF; }</style>
	</head>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 된 상태였다면... %>
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.asp">로그인</a></p>
			<% Else %>
			<% '로그인 안 된 상태였다면... %>
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.asp">로그인</a></p>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.asp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
[그림 6] step4.asp 소스 코드의 실행 화면 (로그아웃 성공)
[그림 7] step4.asp 소스 코드의 실행 화면 (이미 로그아웃된 상태)

step1.asp - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.asp을 살펴보면, 세션으로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.asp에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<%@ Language="VBScript" CodePage="65001" %>
<%
	Response.CharSet="UTF-8"
	Response.CodePage="65001"
	Response.ContentType="text/html;charset=UTF-8"
%>
<%
'###############################################################################
' 사용자 인증 로직
' 이름과 암호를 비교하며 승인되면 True, 승인 안 되면 False를 반환한다.

' 아래 이름의 사용자면 로그인 승인 함.
Const authorizedUsername = "codingCat"
' 아래의 암호를 입력하면 로그인 승인 함.
Const authorizedPassword = "qwerty123456!"

' 로그인 승인 시 True, 아니면 False
Dim authorizeStatus
authorizeStatus = False

' authorizeMembership(trialUsername, trialPassword)
' 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
' trialUsername : 로그인을 시도하는 사용자 이름
' trialPassword : 로그인을 시도하는 사용자가 입력한 암호
' 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
Function authorizeMembership(trialUsername, trialPassword)
	' 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	If StrComp(trialUsername, authorizedUsername) = 0 Then
		' 이름이 일치하면, 암호가 같은지 검사
		If StrComp(trialPassword, authorizedPassword) = 0 Then
			' 이름과 암호가 모두 일치하면 로그인 승인
			authorizeMembership = True
			Exit Function
		End If
	End If
	' 그렇지 않을 경우 로그인 거부
	authorizeMembership = False
End Function
%>
<%
'###############################################################################
' 웹 페이지 헤더 영역
' 쿠키에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

Dim trialUsername
Dim trialPassword

authorizeStatus = False

' 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
If Not IsNull(Request.Cookies("membershipUsername")) Then
	' membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	If Not IsNull(Request.Cookies("membershipPassword")) Then
		' 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		trialUsername = Request.Cookies("membershipUsername")
		trialPassword = Request.Cookies("membershipPassword")
		' membershipUsername과 membershipPassword가 모두 수신되면,
		' 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership(trialUsername, trialPassword)
	End If
End If

' 로그인 요청이 승인되었다면
If authorizeStatus = True Then
	' 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간으로 연장한다.
	' 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	' membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
	' 사용자 이름을 적어 클라이언트로 전송한다.
	Response.Cookies("membershipUsername") = trialUsername
	Response.Expires = DateAdd("h", 12, Now())
	' membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에 
	' 사용자 이름을 적어 클라이언트로 전송한다.
	Response.Cookies("membershipPassword") = trialPassword
	Response.Expires = DateAdd("h", 12, Now())
End If
%>
<%
'###############################################################################
' 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
		<style>a { color: #0000FF; }</style>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<% If authorizeStatus = True Then %>
			<% '로그인 승인 되었다면... %>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="step3.asp">회원 페이지</a></p>
			<% Else %>
			<% '로그인 거부 되었다면... %>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.asp" method="post">
				<label for="trialUsername">사용자 이름 : </label><input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label><input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<% End If %>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.asp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 8] 로그인이 유효한 상태에서 접속하였을 때, step1.asp 소스 코드의 출력 결과


카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
썸네일 이미지
JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
Perl 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을..
Common Gateway Interface/JSP
2018. 9. 19. 13:29

JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Common Gateway Interface/JSP
2018. 9. 19. 13:29

Perl 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part II. 세션을 사용한 로그인, 로그아웃 (Perl)


본 게시물에서는 JSP 소스 코드로 세션에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 서버에 로그인 정보를 보관하고 이 정보에 접근할 수 있는 식별 번호를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 통해 세션 번호를 서버에 전달하고, 서버는 해당 번호의 세션이 보유한 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.jsp - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
	request.setCharacterEncoding("UTF-8");
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
		<style> a { color: #0000FF; } </style>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.jsp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.jsp 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.jsp로 전달할 것이다.

step2.jsp - 사용자 인증


이 페이지는 step1.jsp에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 세션 변수에 각각 아이디와 암호를 보관하고, 해당 세션의 식별번호를 쿠키를 통해 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
	request.setCharacterEncoding("UTF-8");
%>
<%!
/******************************************************************************/
// 사용자 인증 로직
// 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";
// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;

// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역
// 세션에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

String trialUsername = null;
String trialPassword = null;

authorizeStatus = false;

// POST 방식으로 넘어온 데이터 중 trialUsername이라는 데이터가 있는지 확인
if (request.getParameter("trialUsername") != null)
{
	trialUsername = request.getParameter("trialUsername");

	// trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인
	if (request.getParameter("trialPassword") != null)
	{
		trialPassword = request.getParameter("trialPassword");

		// trialUsername과 trialPassword가 모두 수신되면,
		// 위에서 선언한 authorizeMembership 서브루틴을 호출하여 로그인 요청한다.
		authorizeStatus = authorizeMembership
		(
			trialUsername,
			trialPassword
		);
	}
}

// 로그인 요청이 승인되었다면
if (authorizeStatus)
{
	// membershipUsername이라 이름붙인 세션변수에 사용자 이름을 기록한다.
	session.setAttribute("membershipUsername", trialUsername);

	// membershipPassword이라 이름붙인 세션변수에 사용자 암호를 기록한다.
	session.setAttribute("membershipPassword", trialPassword);

	// 세션의 유효기간은 현재 시점으로부터 12시간이다.
	session.setMaxInactiveInterval(12 * 60 * 60);
}
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
		<style> a { color: #0000FF; } </style>
	</head>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% /* 로그인 승인 되었다면... */ %>
			<p>로그인에 성공했습니다.</p>
			<p><a href="./step3.jsp">회원 페이지</a></p>
			<% } else { %>
			<% /* 로그인 거부 되었다면... */ %>
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.jsp">로그인 화면</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.jsp">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.jsp 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.jsp 소스 코드의 실행 화면 (로그인 실패)

JSP의 경우 세션 정보들은 객체의 형태로 메모리에 보관된다.

step3.jsp - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 세션 식별 번호를 전달받는다. 서버의 특정 위치에서 해당 번호를 갖는 세션을 읽어온 후, 로그인 상태임이 확인되면 회원 전용 페이지를 출력한다. 그렇지 않다면 비회원용 페이지를 출력한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
	request.setCharacterEncoding("UTF-8");
%>
<%!
/******************************************************************************/
// 사용자 인증 로직
// 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";
// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;

// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역
// 세션에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

String membershipUsername = null;
String membershipPassword = null;

authorizeStatus = false;

// 로그인 유효성 검사 : 세션에 저장된 로그인 정보를 검증한다.

// 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
if (session.getAttribute("membershipUsername") != null)
{
	// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	if (session.getAttribute("membershipPassword") != null)
	{
		// 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = (String)session.getAttribute("membershipUsername");
		membershipPassword = (String)session.getAttribute("membershipPassword");

		// membershipUsername과 membershipPassword가 모두 수신되면,
		// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership(membershipUsername, membershipPassword);
	}
}

// 로그인 요청이 승인되었다면
if (authorizeStatus)
{
	// membershipUsername이라 이름붙인 세션변수에 사용자 이름을 기록한다.
	session.setAttribute("membershipUsername", membershipUsername);

	// membershipPassword이라 이름붙인 세션변수에 사용자 암호를 기록한다.
	session.setAttribute("membershipPassword", membershipPassword);

	// 세션의 유효기간은 현재 시점으로부터 12시간이다.
	session.setMaxInactiveInterval(12 * 60 * 60);
}
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
		<style> a { color: #0000FF; } </style>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% /* 로그인 승인 되었다면... */ %>
			<p>회원 전용 페이지</p>
			<p>환영합니다. <%=membershipUsername%>님.</p>
			<p>쿠키 문자열 :</p>
			<% for (java.util.Enumeration<String> e = request.getHeaders("Cookie"); e.hasMoreElements(); ) { %>
			<pre><code><%=e.nextElement()%></code></pre>
			<% } %>
			<p><a href="./step4.jsp">로그아웃</a></p>
			<% } else { %>
			<% /* 로그인 거부 되었다면... */ %>
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.jsp">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.jsp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 4] step3.jsp 소스 코드의 실행 화면 (로그인 성공)
[그림 5] step3.jsp 소스 코드의 실행 화면 (로그인 실패)

step4.jsp - 로그아웃 화면


로그인 상태임이 확인되면 서버의 세션을 삭제하고 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
	request.setCharacterEncoding("UTF-8");
%>
<%!
/******************************************************************************/
// 사용자 인증 로직
// 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";
// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;

// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

String membershipUsername = null;
String membershipPassword = null;

authorizeStatus = false;

// 로그인 유효성 검사 : 세션에 저장된 로그인 정보를 검증한다.

// 세션 변수 중에 membershipUsername이라는 데이터가 있는지 확인
if (session.getAttribute("membershipUsername") != null)
{
	// 세션 변수 중에 membershipPassword이라는 데이터가 있는지 확인
	if (session.getAttribute("membershipPassword") != null)
	{
		// 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = (String)session.getAttribute("membershipUsername");
		membershipPassword = (String)session.getAttribute("membershipPassword");

		// membershipUsername과 membershipPassword가 모두 수신되면,
		// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership
		(
			membershipUsername,
			membershipPassword
		);
	}
}

// 로그아웃은 로그인 여부와 무관하게 수행된다.
// 세션 객체를 삭제함
session.removeAttribute("membershipUsername");
session.removeAttribute("membershipPassword");
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>4 단계 : 로그아웃</title>
		<style> a { color: #0000FF; } </style>
	</head>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% /* 로그인 된 상태였다면 ... */ %>
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.jsp">로그인</a></p>
			<% } else { %>
			<% /* 로그인 안 된 상태였다면... */ %>
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.jsp">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.jsp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
[그림 6] step4.jsp 소스 코드의 실행 화면 (로그아웃 성공)
[그림 7] step4.jsp 소스 코드의 실행 화면 (이미 로그아웃된 상태)

step1.jsp - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.jsp을 살펴보면, 세션으로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.jsp에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
	request.setCharacterEncoding("UTF-8");
%>
<%!
/******************************************************************************/
// 사용자 인증 로직
// 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";
// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;

// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역
// 세션에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

String membershipUsername = null;
String membershipPassword = null;
Cookie objectUsername = null;
Cookie objectPassword = null;

authorizeStatus = false;

// 로그인 유효성 검사 : 세션에 저장된 로그인 정보를 검증한다.

// 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
if (session.getAttribute("membershipUsername") != null)
{
	// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	if (session.getAttribute("membershipPassword") != null)
	{
		// 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		membershipUsername = (String)session.getAttribute("membershipUsername");
		membershipPassword = (String)session.getAttribute("membershipPassword");

		// membershipUsername과 membershipPassword가 모두 수신되면,
		// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership
		(
			membershipUsername,
			membershipPassword
		);
	}
}

// 로그인 요청이 승인되었다면
if (authorizeStatus)
{
	// membershipUsername이라 이름붙인 세션 변수에
	// 사용자 이름을 기록한다.
	session.setAttribute("membershipUsername", membershipUsername);

	// membershipPassword이라 이름붙인 세션 변수에
	// 사용자 암호를 기록한다.
	session.setAttribute("membershipPassword", membershipPassword);

	// 세션의 유효기간을 현재 시점으로부터 12시간으로 연장한다. [단위: 초]
	session.setMaxInactiveInterval(12 * 60 * 60);
}
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
		<style> a { color: #0000FF; } </style>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% /* 로그인 승인 되었다면... */ %>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="step3.jsp">회원 페이지</a></p>
			<% } else { %>
			<% /* 로그인 거부 되었다면... */ %>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.jsp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 8] 로그인이 유효한 상태에서 접속하였을 때, step1.jsp 소스 코드의 출력 결과
카테고리 “Common Gateway Interface/JSP”
more...
썸네일 이미지
JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
Perl 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을..
Common Gateway Interface/JSP
2018. 9. 16. 21:43

JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)

Common Gateway Interface/JSP
2018. 9. 16. 21:43

Perl 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part I. 쿠키를 사용한 로그인, 로그아웃 (Perl)


본 게시물에서는 JSP 소스 코드로 쿠키에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 이 정보를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 서버에 전달하고, 서버는 쿠키의 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.jsp - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.jsp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.jsp 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.jsp로 전달할 것이다.

step2.jsp - 사용자 인증


이 페이지는 step1.jsp에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 쿠키 변수에 각각 아이디와 암호를 보관하여 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%!
/******************************************************************************/
// 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";

// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;
	
// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

String trialUsername = null;
String trialPassword = null;

// 클라이언트로 전송할 쿠키이다.
Cookie objectUsername = null;
// 클라이언트로 전송할 쿠키이다.
Cookie objectPassword = null;

authorizeStatus = false;
request.setCharacterEncoding("UTF-8");

// POST 방식으로 넘어온 데이터 중 trialUsername이라는 데이터가 있는지 확인
if (request.getParameter("trialUsername") != null)
{
	trialUsername = request.getParameter("trialUsername");

	// trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인
	if (request.getParameter("trialPassword") != null)
	{
		trialPassword = request.getParameter("trialPassword");

		// trialUsername과 trialPassword가 모두 수신되면,
		// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		authorizeStatus = authorizeMembership
		(
			trialUsername,
			trialPassword
		);
	}
}

// 로그인 요청이 승인되었다면
if (authorizeStatus)
{
	// membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에
	// 사용자 이름을 기록한다.
	objectUsername = new Cookie("membershipUsername", trialUsername);
	objectUsername.setMaxAge(12 * 60 * 60);
	objectUsername.setPath("/");

	// membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에
	// 사용자 암호를 기록한다.
	objectPassword = new Cookie("membershipPassword", trialPassword);
	objectPassword.setMaxAge(12 * 60 * 60);
	objectPassword.setPath("/");

	// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	response.addCookie(objectUsername);
	response.addCookie(objectPassword);
}
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
	</head>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% // 로그인 승인 되었다면... %>
			<p>로그인에 성공했습니다.</p>
			<p>쿠키 문자열</p>
			<% for (String cookie : response.getHeaders("Set-Cookie")) { %>
			<pre><code><%=cookie%></code></pre>
			<% } %>
			<p><a href="./step3.jsp">회원 페이지</a></p>
			<% } else { %>
			<% // 로그인 거부 되었다면... %>
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.jsp">로그인 화면</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.jsp">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.jsp 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.jsp 소스 코드의 실행 화면 (로그인 실패)

위 소스 코드는 이전 페이지(step1.jsp)에서 POST 방식으로 전달된 두 데이터(trialUsername, trialPassword)를 읽어와서 로그인을 수행하는 예이다. 통상 이런 종류의 예는 회원 정보를 기록하고 있는 데이터베이스에 접속하여 아이디와 패스워드를 비교하지만, 소스 코드의 단순화를 위해 이를 하드코딩하였다.

로그인을 허용할 사용자의 이름이 "codingCat"이고 이를 변수 authorizedUsername에 보관한다. 마찬가지로 접속 암호는 "qwerty123456!"이라 하고 이를 변수 authorizedPassword에 보관한다.

로그인 유효성 검사를 수행할 서브루틴은 authorizeMembership(trialUsername, trialPassword);으로 정의하였다. 이 서브루틴에서는 매개변수(-trialUsername, -trialPassword)로 받아들인 사용자 이름과 암호가 미리 정의된 값(authorizedUsername, authorizedPassword)과 동일한지 여부를 검사하여 일치하면 true를 반환하고 일치하지 않으면 false를 반환한다.

authorizeMembership 서브루틴이 false를 반환하면 이를 변수 authorizeStatus에 보관한다. 이 값의 true에 따라 웹 페이지 본문에서 로그인 성공 또는 실패 화면 중 하나를 선택하여 보여주게 될 것이다. 이 때 중요한 것은 쿠키의 생성이다. 쿠키는 HTTP 헤더 부분에 Set-Cookie 항목으로써 나타나야 한다. 즉, 웹 페이지 본문을 출력하는 도중에 쿠키를 클라이언트로 전송하는 것이 불가능하다. 그러므로 로그인 승인 여부를 가장 처음에 확인한 후 웹 페이지를 시작하는 것이다. 로그인 성공 시 유효기간 12시간짜리의 membershipUsername, membershipPassword 쿠키변수를 생성하여 로그인이 허용된 사용자 이름과 암호를 보관하고 이를 클라이언트로 전달한다.

로그인이 성공하면 서버에서 클라이언트로 쿠키가 전달되는데, 그 내용은 다음과 같이 확인 가능하며 본 소스 코드에서 기록한 사용자 이름과 암호를 그대로 볼 수 있음을 확인할 수 있다.

[그림 4] step2.cgi 소스 코드의 실행 결과 생성된 쿠키

step3.jsp - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 아이디와 암호를 전달받는다. 로그인 상태임이 확인되면 회원 전용 페이지를 출력하고, 그렇지 않다면 비회원용 페이지를 출력한다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%!
/******************************************************************************/
// 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";

// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;
	
// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

String membershipUsername = null;
String membershipPassword = null;

// 클라이언트로 전송할 쿠키이다.
Cookie objectUsername = null;
// 클라이언트로 전송할 쿠키이다.
Cookie objectPassword = null;

authorizeStatus = false;
request.setCharacterEncoding("UTF-8");

// 쿠키가 존재하면
// 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (request.getCookies() != null)
{
	// 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
	for (Cookie cookie : request.getCookies())
	{
		if (cookie.getName().equals("membershipUsername"))
		{
			objectUsername = cookie;
			break;
		}
	}

	// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	if (objectUsername != null)
	{
		for (Cookie cookie : request.getCookies())
		{
			if (cookie.getName().equals("membershipPassword"))
			{
				objectPassword = cookie;
				break;
			}
		}

		if (objectPassword != null)
		{
			// 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
			membershipUsername = objectUsername.getValue();
			membershipPassword = objectPassword.getValue();

			// membershipUsername과 membershipPassword가 모두 수신되면,
			// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
			authorizeStatus = authorizeMembership
			(
				membershipUsername,
				membershipPassword
			);
		}
	}
}

// 로그인 요청이 승인되었다면
if (authorizeStatus)
{
	// 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간으로 연장한다.

	// membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에
	// 사용자 이름을 기록한다.
	objectUsername = new Cookie("membershipUsername", membershipUsername);
	objectUsername.setMaxAge(12 * 60 * 60);
	objectUsername.setPath("/");

	// membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에
	// 사용자 암호를 기록한다.
	objectPassword = new Cookie("membershipPassword", membershipPassword);
	objectPassword.setMaxAge(12 * 60 * 60);
	objectPassword.setPath("/");

	// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	response.addCookie(objectUsername);
	response.addCookie(objectPassword);
}
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% // 로그인 승인 되었다면... %>
			<p>회원 전용 페이지</p>
			<p>환영합니다. <%=membershipUsername%>님.</p>
			<p>쿠키 문자열 :</p>
			<% for (java.util.Enumeration<String> e = request.getHeaders("Cookie"); e.hasMoreElements(); ) { %>
			<pre><code><%=e.nextElement()%></code></pre>
			<% } %>
			<p><a href="./step4.jsp">로그아웃</a></p>
			<% } else { %>
			<% // 로그인 거부 되었다면... %>
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.jsp">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.jsp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 5] step3.jsp 소스 코드의 실행 화면 (로그인 성공)
[그림 6] step3.jsp 소스 코드의 실행 화면 (로그인 실패)

위 소스 코드는 클라이언트 측 쿠키에 보관된 쿠키 변수 중 membershipUsernamemembershipPassword를 읽어와서 로그인 유효성 검사를 수행하고, 로그인 검증이 끝나면 쿠키의 유효기간이 연장되어 있음을 확인할 수 있다.

step4.jsp - 로그아웃 화면


로그인 상태임이 확인되면 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%!
/******************************************************************************/
// 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";

// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;
	
// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역 : 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

String membershipUsername = null;
String membershipPassword = null;

// 클라이언트로 전송할 쿠키이다.
Cookie objectUsername = null;
// 클라이언트로 전송할 쿠키이다.
Cookie objectPassword = null;

authorizeStatus = false;
request.setCharacterEncoding("UTF-8");


// 쿠키가 존재하면
// 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (request.getCookies() != null)
{
	// 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
	for (Cookie cookie : request.getCookies())
	{
		if (cookie.getName().equals("membershipUsername"))
		{
			objectUsername = cookie;
			break;
		}
	}

	// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	if (objectUsername != null)
	{
		for (Cookie cookie : request.getCookies())
		{
			if (cookie.getName().equals("membershipPassword"))
			{
				objectPassword = cookie;
				break;
			}
		}

		if (objectPassword != null)
		{
			// 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
			membershipUsername = objectUsername.getValue();
			membershipPassword = objectPassword.getValue();

			// membershipUsername과 membershipPassword가 모두 수신되면,
			// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
			authorizeStatus = authorizeMembership
			(
				membershipUsername,
				membershipPassword
			);
		}
	}
}

// 로그아웃은 로그인 여부와 무관하게 수행된다.

// membershipUsername이라 이름붙인 유효기간 만료된 쿠키변수에
// 사용자 이름을 적어 클라이언트로 전송한다.
objectUsername = new Cookie("membershipUsername", membershipUsername);
objectUsername.setMaxAge(0);
objectUsername.setPath("/");

// membershipPassword이라 이름붙인 유효기간 만료된 쿠키변수에
// 사용자 암호를 적어 클라이언트로 전송한다.
objectPassword = new Cookie("membershipPassword", membershipPassword);
objectPassword.setMaxAge(0);
objectPassword.setPath("/");

// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
response.addCookie(objectUsername);
response.addCookie(objectPassword);
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>4 단계 : 로그아웃</title>
	</head>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<% if (authorizeStatus) { %>
			<% // 로그인 된 상태였다면 ... %>
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.jsp">로그인</a></p>
			<% } else { %>
			<% // 로그인 안 된 상태였다면... %>
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.jsp">로그인</a></p>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.jsp">1 단계(로그인)</a> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step2.jsp">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
|_##]
[그림 7] step4.jsp 소스 코드의 실행 화면 (로그아웃 성공)
|_##]
[그림 8] step4.jsp 소스 코드의 실행 화면 (이미 로그아웃된 상태)

로그아웃은 쿠키에서 해당 변수(membershipUsername, membershipPassword)를 삭제하는 과정인데 그 방법은 유효기간을 과거로 설정하여 클라이언트에게 덮어쓰도록 전송하는 것이다. 본 소스코드에서는 재차 로그인 할 때 발생할 수 있는 오류를 방지하고자, 로그인 상태와 관계 없이 두 쿠키 변수를 삭제하도록 구성해보았다. 로그인 상태를 나타내는 변수(authorizeStatus)는 단순히 안내 메시지의 선택을 위해서만 사용되었다. step4.cgi의 로그아웃 결과, 클라이언트에서 두 개의 쿠키변수가 사라졌음을 다음과 같이 확인할 수 있다.

[그림 9] step4.cgi 소스 코드의 실행 결과 쿠키가 삭제된 상태

step1.jsp - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.cgi을 살펴보면, 쿠키로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.cgi에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%!
/******************************************************************************/
// 사용자 인증 로직 : 이름과 암호를 비교하며 승인되면 true, 승인 안 되면 false를 반환한다.

// 아래 이름의 사용자면 로그인 승인 함
private static final String authorizedUsername = "codingCat";
// 아래의 암호를 입력하면 로그인 승인 함
private static final String authorizedPassword = "qwerty123456!";

// 로그인 승인 시 true, 아니면 false
private boolean authorizeStatus = false;
	
// authorizeMembership(String trialUsername, String trialPassword)
// 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
// trialUsername : 로그인을 시도하는 사용자 이름
// trialPassword : 로그인을 시도하는 사용자가 입력한 암호
// 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
private static boolean authorizeMembership(String trialUsername, String trialPassword)
{
	// 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (authorizedUsername.equals(trialUsername))
	{
		// 이름이 일치하면, 암호가 같은지 검사
		if (authorizedPassword.equals(trialPassword)) 
		{
			// 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	// 그렇지 않을 경우 로그인 거부
	return false;
}
%>
<%
/******************************************************************************/
// 웹 페이지 헤더 영역
// 쿠키에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

String membershipUsername = null;
String membershipPassword = null;

// 클라이언트로 전송할 쿠키이다.
Cookie objectUsername = null;
// 클라이언트로 전송할 쿠키이다.
Cookie objectPassword = null;

authorizeStatus = false;
request.setCharacterEncoding("UTF-8");

// 쿠키가 존재하면
// 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (request.getCookies() != null)
{
	// 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
	for (Cookie cookie : request.getCookies())
	{
		if (cookie.getName().equals("membershipUsername"))
		{
			objectUsername = cookie;
			break;
		}
	}

	// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
	if (objectUsername != null)
	{
		for (Cookie cookie : request.getCookies())
		{
			if (cookie.getName().equals("membershipPassword"))
			{
				objectPassword = cookie;
				break;
			}
		}

		if (objectPassword != null)
		{
			// 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
			membershipUsername = objectUsername.getValue();
			membershipPassword = objectPassword.getValue();

			// membershipUsername과 membershipPassword가 모두 수신되면,
			// 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
			authorizeStatus = authorizeMembership
			(
				membershipUsername,
				membershipPassword
			);
		}
	}
}

// 로그인 요청이 승인되었다면
if (authorizeStatus)
{
	// 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간으로 연장한다.

	// membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키변수에
	// 사용자 이름을 기록한다.
	objectUsername = new Cookie("membershipUsername", membershipUsername);
	objectUsername.setMaxAge(12 * 60 * 60);
	objectUsername.setPath("/");

	// membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키변수에
	// 사용자 암호를 기록한다.
	objectPassword = new Cookie("membershipPassword", membershipPassword);
	objectPassword.setMaxAge(12 * 60 * 60);
	objectPassword.setPath("/");

	// 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	response.addCookie(objectUsername);
	response.addCookie(objectPassword);
}
%>
<%
/******************************************************************************/
// 웹 페이지 본문 영역
%>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<% if(authorizeStatus) { %>
			<% // 로그인 승인 되었다면... %>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="./step3.jsp">회원 페이지</a></p>
			<% } else { %>
			<% // 로그인 거부 되었다면... %>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.jsp" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<% } %>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.jsp">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.jsp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.jsp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>


_
[그림 10] 로그인이 유효한 상태에서 접속하였을 때, step1.cgi 소스 코드의 출력 결과


카테고리 “Common Gateway Interface/JSP”
more...
썸네일 이미지
PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
PHP 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 ..
Common Gateway Interface/PHP
2018. 9. 15. 20:22

PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Common Gateway Interface/PHP
2018. 9. 15. 20:22

PHP 로그인 로그아웃 예제 정리


본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다.

  1. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  2. Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  3. PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  4. PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  5. JSP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  6. JSP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  7. ASP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  8. ASP 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
  9. ASP.NET 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예)
  10. ASP.NET 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]

Part II. 세션을 사용한 로그인, 로그아웃 (PHP)


본 게시물에서는 PHP 소스 코드로 세션에 의한 로그인/로그아웃 기능을 구현한다. 로그인 화면에서 아이디와 암호를 맞게 입력했다면 서버에 로그인 정보를 보관하고 이 정보에 접근할 수 있는 식별 번호를 클라이언트의 쿠키로 전송한다. 이후 클라이언트는 페이지를 접속할 때마다 쿠키를 통해 세션 번호를 서버에 전달하고, 서버는 해당 번호의 세션이 보유한 유효성 여부를 판별하여 회원 페이지를 보여줄 것인지, 비회원 페이지를 보여줄 것인지를 결정하게 된다.

step1.phtml - 로그인 화면


이 페이지를 통해 사용자로부터 아이디와 암호를 입력받는다. 아이디가 전달될 매개변수 이름은 trialUsername이라 하고 암호가 전달될 매개변수 이름은 trialPassword라 이름 붙인다. 예제 소스 코드의 구조를 단순하게 하기 위하여 아이디와 암호에 대한 보안 조치 등은 생략한 채 쿠키와 POST 데이터를 통해 직접 사용자 이름과 암호가 전달될 것이다.

<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.phtml" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.phtml">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.phtml">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.phtml">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 1] step1.phtml 소스 코드의 실행 화면

위 소스 코드에서는 사용자 이름과 암호를 입력받는 폼form을 출력한다. name 속성이 각각 trialUsernametrialPasswordinput을 통해 사용자 이름과 암호를 입력받은 뒤 POST 방식으로 다음 파일인 step2.phtml로 전달할 것이다.

step2.phtml - 사용자 인증


이 페이지는 step1.phtml에서 전달된 아이디(trialUsername)/암호(trialPassword)가 미리 준비된 아이디(authorizedUsername)/암호(authorizedPassword)와 일치하는지 여부를 검사할 것이다. 일치하면 membershipUsernamemembershipPassword라는 세션 변수에 각각 아이디와 암호를 보관하고, 해당 세션의 식별번호를 쿠키를 통해 클라이언트로 전송할 것이다. 일치하지 않으면 별도의 오류 메시지를 보여줄 것이다.

<?php
################################################################################
# 사용자 인증 로직
# 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다.

# 세션의 유효 기간은 현재 시점으로부터 12시간이다. [단위: 분]
# (session_start보다 먼저 호출되어야 함)
session_cache_expire(12 * 60);

# 세션을 사용하려면 가장 첫 줄에 호출되어야 할 함수
session_start();

# 아래 이름의 사용자면 로그인 승인 함
$authorizedUsername = "codingCat";
# 아래의 암호를 입력하면 로그인 승인 함
$authorizedPassword = "qwerty123456!";
# 로그인 승인 시 nonzero, 아니면 zero
$authorizeStatus = 0;

# authorizeMembership($trialUsername, $trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
# $trialUsername : 로그인을 시도하는 사용자 이름
# $trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
function authorizeMembership($trialUsername, $trialPassword)
{
	global $authorizedUsername;
	global $authorizedPassword;
		
	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (strcmp($trialUsername, $authorizedUsername) == 0)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if (strcmp($trialPassword, $authorizedPassword) == 0)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return false;
}
?>
<?php
################################################################################
# 웹 페이지 헤더 영역
# 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

$trialUsername = null;
$trialPassword = null;

$authorizeStatus = 0;

# POST 방식으로 전달된 데이터 중 trialUsername이라는 데이터가 있는지 확인
if ($_POST["trialUsername"] != null)
{
	# trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인 
	if ($_POST["trialPassword"] != null)
	{
		# POST 데이터에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$trialUsername = $_POST["trialUsername"];
		$trialPassword = $_POST["trialPassword"];

		# trialUsername과 trialPassword가 모두 수신되면,
		# 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		$authorizeStatus = authorizeMembership
		(
			$trialUsername,
			$trialPassword
		);
	}
}

# 로그인 요청이 승인되었다면
if ($authorizeStatus)
{
	# membershipUsername이라 이름붙인 세션 변수에
	# 사용자 이름을 기록한다.
	$_SESSION["membershipUsername"] = $trialUsername;

	# membershipPassword이라 이름붙인 세션 변수에
	# 사용자 암호를 기록한다.
	$_SESSION["membershipPassword"] = $trialPassword;
}
?>
<?php
################################################################################
# 웹 페이지 본문 영역
?>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>2 단계 : 사용자 인증</title>
	</head>
	<body>
		<header>
			<h1>2 단계 : 사용자 인증</h1>
		</header>
		<hr />
		<section>
			<?php if ($authorizeStatus) : ?>
			<?php /* 로그인 승인 되었다면... */ ?>
			<p>로그인에 성공했습니다.</p>
			<p>쿠키 문자열</p>
			<pre><code><?php print_r($_COOKIE); ?></code></pre>
			<p><a href="./step3.phtml">회원 페이지</a></p>
			<p>세션 문자열</p>
			<pre><code><?php print_r($_SESSION); ?></code></pre>
			<p><a href="./step3.phtml">회원 페이지</a></p>
			<?php else : ?>
			<?php /* 로그인 거부 되었다면... */ ?>
			<p>로그인에 실패했습니다.</p>
			<p><a href="./step1.phtml">로그인 화면</a></p>
			<?php endif ?>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.phtml">1 단계(로그인)</a> | </span>
				<span><strong>2 단계(사용자 인증)</strong> | </span>
				<span><a href="./step3.asp">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.asp">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.cgi 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.cgi 소스 코드의 실행 화면 (로그인 실패)

로그인이 정상적이라면 서버의 특정 경로에 세션에 대한 데이터가 생성되어있음을 확인할 수 있다. CentOS를 기준으로 /var/lib/php/session이다. 세션이 유지되는 동안 root 권한으로 이 디렉터리를 들어가면 sess_<세션식별번호>라는 이름의 텍스트 파일이 아래와 같이 존재할 것이다.

[그림 4] 세션 정보를 담은 텍스트 파일의 확인

vi로 이 파일을 열었을 때 다음과 같이 사용자 이름, 사용자 암호, 만료시간 등의 각종 세션변수가 기록되어 있음을 확인할 수 있다. 쿠키를 사용하여 클라이언트로 전달되는 내용은 아래의 내용 자체가 아니라 아래의 내용에 접근할 수 있는 고유번호만을 전달할 뿐이므로 쿠키만을 사용하는 로그인보다는 안전하다고 볼 수 있다.

[그림 5] 세션 파일의 내용

세션은 고유의 아이디로써 관리되는데, PHP에서 클라이언트에 전달하는 세션의 식별 아이디는 PHPSESSID라는 이름의 쿠키 변수로 전달된다.

step3.phtml - 회원 전용 페이지


클라이언트 측으로부터 쿠키에 보관된 세션 식별 번호를 전달받는다. 서버의 특정 위치에서 해당 번호를 갖는 세션을 읽어온 후, 로그인 상태임이 확인되면 회원 전용 페이지를 출력한다. 그렇지 않다면 비회원용 페이지를 출력한다.

<?php
################################################################################
# 사용자 인증 로직
# 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다.

# 세션의 유효 기간은 현재 시점으로부터 12시간이다. [단위: 분]
# (session_start보다 먼저 호출되어야 함)
session_cache_expire(12 * 60);

# 세션을 사용하려면 가장 첫 줄에 호출되어야 할 함수
session_start();

# 아래 이름의 사용자면 로그인 승인 함
$authorizedUsername = "codingCat";
# 아래의 암호를 입력하면 로그인 승인 함
$authorizedPassword = "qwerty123456!";
# 로그인 승인 시 nonzero, 아니면 zero
$authorizeStatus = 0;

# authorizeMembership($trialUsername, $trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
# $trialUsername : 로그인을 시도하는 사용자 이름
# $trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
function authorizeMembership($trialUsername, $trialPassword)
{
	global $authorizedUsername;
	global $authorizedPassword;
		
	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (strcmp($trialUsername, $authorizedUsername) == 0)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if (strcmp($trialPassword, $authorizedPassword) == 0)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return false;
}
?>
<?php
################################################################################
# 웹 페이지 헤더 영역
# 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

$membershipUsername = null;
$membershipPassword = null;

	# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.	
	# 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
	if ($_SESSION["membershipUsername"] != null)
	{
		# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
		if ($_SESSION["membershipPassword"] != null)
		{
			# 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
			$membershipUsername = $_SESSION["membershipUsername"];
			$membershipPassword = $_SESSION["membershipPassword"];

			# membershipUsername과 membershipPassword가 모두 수신되면,
			# 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
			$authorizeStatus = authorizeMembership
			(
				$membershipUsername,
				$membershipPassword
			);
		}
	}
?>
<?php
################################################################################
# 웹 페이지 본문 영역
?>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>3 단계 : 회원 페이지</title>
	</head>
	<body>
		<header>
			<h1>3 단계 : 회원 페이지</h1>
		</header>
		<hr />
		<section>
			<?php if ($authorizeStatus) : ?>
			<?php /* 로그인 승인 되었다면... */ ?>
			<p>회원 전용 페이지</p>
			<p>환영합니다. <?=$membershipUsername;?>님.</p>
			<p>쿠키 문자열 :</p>
			<pre><code><?php print_r($_COOKIE); ?></code></pre>
			<p>세션 문자열 :</p>
			<pre><code><?php print_r($_SESSION); ?></code></pre>
			<p><a href="./step4.phtml">로그아웃</a></p>
			<?php else : ?>
			<?php /* 로그인 거부 되었다면... */ ?>
			<p>이 페이지를 보려면 로그인이 필요합니다.</p>
			<p><a href="./step1.phtml">로그인</a></p>
			<?php endif ?>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.phtml">1 단계(로그인)</a> | </span>
				<span><a href="./step2.phtml">2 단계(사용자 인증)</a> | </span>
				<span><strong>3 단계(회원 페이지)</strong> | </span>
				<span><a href="./step4.phtml">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 6] step3.cgi 소스 코드의 실행 화면 (로그인 성공)
[그림 7] step3.cgi 소스 코드의 실행 화면 (로그인 실패)

step4.phtml - 로그아웃 화면


로그인 상태임이 확인되면 서버의 세션을 삭제하고 클라이언트의 쿠키를 만료시켜서 로그아웃 작업을 수행한다. 그렇지 않은 경우 이미 로그아웃 상태임을 알려준다.

<?php
################################################################################
# 사용자 인증 로직
# 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다.

# 세션의 유효 기간은 현재 시점으로부터 12시간이다. [단위: 분]
# (session_start보다 먼저 호출되어야 함)
session_cache_expire(12 * 60);

# 세션을 사용하려면 가장 첫 줄에 호출되어야 할 함수
session_start();

# 아래 이름의 사용자면 로그인 승인 함
$authorizedUsername = "codingCat";
# 아래의 암호를 입력하면 로그인 승인 함
$authorizedPassword = "qwerty123456!";
# 로그인 승인 시 nonzero, 아니면 zero
$authorizeStatus = 0;

# authorizeMembership($trialUsername, $trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
# $trialUsername : 로그인을 시도하는 사용자 이름
# $trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
function authorizeMembership($trialUsername, $trialPassword)
{
	global $authorizedUsername;
	global $authorizedPassword;
		
	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (strcmp($trialUsername, $authorizedUsername) == 0)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if (strcmp($trialPassword, $authorizedPassword) == 0)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return false;
}
?>
<?php
################################################################################
# 웹 페이지 헤더 영역
# 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

$membershipUsername = null;
$membershipPassword = null;

# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
# 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
if ($_SESSION["membershipUsername"] != null)
{
	# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	if ($_SESSION["membershipPassword"] != null)
	{
		# 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$membershipUsername = $_SESSION["membershipUsername"];
		$membershipPassword = $_SESSION["membershipPassword"];

		# membershipUsername과 membershipPassword가 모두 수신되면,
		# 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		$authorizeStatus = authorizeMembership
		(
			$membershipUsername,
			$membershipPassword
		);
	}
}

# 로그아웃은 로그인 여부와 무관하게 수행된다.

# membershipUsername이라 이름붙인 세션 변수에
# 사용자 이름을 기록한다.
$_SESSION["membershipUsername"] = "<undefined>";

# membershipPassword이라 이름붙인 세션 변수에
# 사용자 암호를 기록한다.
$_SESSION["membershipPassword"] = "<undefined>";

# 세션 객체를 삭제함
session_destroy();
?>
<?php
################################################################################
# 웹 페이지 본문 영역
?>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>4 단계 : 로그아웃</title>
	</head>
	<body>
		<header>
			<h1>4 단계 : 로그아웃</h1>
		</header>
		<hr />
		<section>
			<?php if ($authorizeStatus) : ?>
			<?php /* 로그인 된 상태였다면 ... */ ?>
			<p>로그아웃되었습니다.</p>
			<p><a href="./step1.phtml">로그인</a></p>
			<?php else : ?>
			<?php /* 로그인 안 된 상태였다면... */ ?>
			<p>로그인되어있지 않습니다.</p>
			<p><a href="./step1.phtml">로그인</a></p>
			<?php endif ?>
		</section>
		<hr />
		<footer>
			<p>
				<span><a href="./step1.phtml">1 단계(로그인)</a> | </span>
				<span><a href="./step2.phtml">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.phtml">3 단계(회원 페이지)</a> | </span>
				<span><strong>4 단계(로그아웃)</strong></span>
			</p>
		</footer>
	</body>
</html>
[그림 8] step4.cgi 소스 코드의 실행 화면 (로그아웃 성공)
[그림 9] step4.cgi 소스 코드의 실행 화면 (이미 로그아웃된 상태)

본 소스 코드의 실행 결과 서버에 보관되어있던 세션도 삭제되었음을 확인할 수 있다.

[그림 10] step4.cgi 소스 코드의 실행 결과 세션이 삭제된 상태

step1.phtml - 중복 로그인을 방지하기 위한 소스 코드의 수정


앞서 작성한 step3.phtml을 살펴보면, 세션으로부터 사용자 이름과 암호를 읽은 후 로그인 유효성을 재검증하는 부분이 있다. 로그인이 재차 승인되면 쿠키의 유효기간이 연장되면서 회원 전용 페이지를 보여주고 그렇지 않으면 로그인 화면으로 안내하는 메시지를 보여주는데 이를 step1.phtml에 적용해본다. 중복 로그인을 방지하기 위해 쿠키를 읽어들이고 이미 로그인이 유효한 상태라면 곧바로 회원 페이지로 넘어갈 수 있도록 안내하는 기능이 추가된다.

<?php
################################################################################
# 사용자 인증 로직
# 이름과 암호를 비교하며 승인되면 nonzero, 승인 안 되면 zero를 반환한다.

# 세션의 유효 기간은 현재 시점으로부터 12시간이다. [단위: 분]
# (session_start보다 먼저 호출되어야 함)
session_cache_expire(12 * 60);

# 세션을 사용하려면 가장 첫 줄에 호출되어야 할 함수
session_start();

# 아래 이름의 사용자면 로그인 승인 함
$authorizedUsername = "codingCat";
# 아래의 암호를 입력하면 로그인 승인 함
$authorizedPassword = "qwerty123456!";
# 로그인 승인 시 nonzero, 아니면 zero
$authorizeStatus = 0;

# authorizeMembership($trialUsername, $trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴
# $trialUsername : 로그인을 시도하는 사용자 이름
# $trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 true를 반환하고, 승인 거부 시 false를 반환한다.
function authorizeMembership($trialUsername, $trialPassword)
{
	global $authorizedUsername;
	global $authorizedPassword;
		
	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if (strcmp($trialUsername, $authorizedUsername) == 0)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if (strcmp($trialPassword, $authorizedPassword) == 0)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return true;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return false;
}
?>
<?php
################################################################################
# 웹 페이지 헤더 영역
# 세션에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

$membershipUsername = null;
$membershipPassword = null;

# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.	
# 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
if ($_SESSION["membershipUsername"] != null)
{
	# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	if ($_SESSION["membershipPassword"] != null)
	{
		# 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$membershipUsername = $_SESSION["membershipUsername"];
		$membershipPassword = $_SESSION["membershipPassword"];

		# membershipUsername과 membershipPassword가 모두 수신되면,
		# 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
		$authorizeStatus = authorizeMembership
		(
			$membershipUsername,
			$membershipPassword
		);
	}
}

# 로그인 요청이 승인되었다면
if ($authorizeStatus)
{
	# membershipUsername이라 이름붙인 세션 변수에
	# 사용자 이름을 기록한다.
	$_SESSION["membershipUsername"] = $membershipUsername;

	# membershipPassword이라 이름붙인 세션 변수에
	# 사용자 암호를 기록한다.
	$_SESSION["membershipPassword"] = $membershipPassword;
}
?>
<?php
################################################################################
# 웹 페이지 본문 영역
?>
<!DOCTYPE html>
<html lang="ko">
	<head>
		<meta charset="UTF-8" />
		<title>1 단계 : 로그인</title>
	</head>
	<body>
		<header>
			<h1>1 단계 : 로그인</h1>
		</header>
		<hr />
		<section>
			<?php if($authorizeStatus) : ?>
			<?php /* 로그인 승인 되었다면... */ ?>
			<p>이미 로그인되어 있습니다.</p>
			<p><a href="./step3.phtml">회원 페이지</a></p>
			<?php else : ?>
			<?php /* 로그인 거부 되었다면... */ ?>
			<p>사용자 이름과 사용자 암호를 입력하세요.</p>
			<form action="./step2.phtml" method="post">
				<label for="trialUsername">사용자 이름 : </label>
				<input type="text" id="trialUsername" name="trialUsername" />
				<label for="trialPassword">사용자 암호 : </label>
				<input type="password" id="trialPassword" name="trialPassword" />
				<input type="submit" />
			</form>
			<?php endif ?>
		</section>
		<hr />
		<footer>
			<p>
				<span><strong>1 단계(로그인)</strong> | </span>
				<span><a href="./step2.phtml">2 단계(사용자 인증)</a> | </span>
				<span><a href="./step3.phtml">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.phtml">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 11] 로그인이 유효한 상태에서 접속하였을 때, step1.phtml 소스 코드의 출력 결과


카테고리 “Common Gateway Interface/PHP”
more...

“분류 전체보기” (134건)