^(코딩캣)^ = @"코딩"하는 고양이;
썸네일 이미지
[Classic ASP] SubFolders, Files : 로컬 내 파일과 폴더 목록 얻기
서버 내 로컬 경로에서 파일과 폴더는 다음과 같이 얻을 수 있다. Scripting.FileSystemObject 객체 할당 및 해제 Scripting.FileSystemObject 객체는 컴퓨터(서버) 내 파일 시스템에 접근할 수 있는 메소드들을 제공하는 객체이다(출처: https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object). GetFolder 메소드로 폴더에 대한 객체 얻기 [Scripting.FileSystemObject].GetFolder 메소드는 폴더를 특정하는 경로를 받아서 이에 대한 객체를 반환한다. 이 때, 경로는 하드코딩도 되겠으나, Server.Ma..
Common Gateway Interface/ASP & ASP.NET
2023. 3. 19. 08:41

[Classic ASP] SubFolders, Files : 로컬 내 파일과 폴더 목록 얻기

Common Gateway Interface/ASP & ASP.NET
2023. 3. 19. 08:41

서버 내 로컬 경로에서 파일과 폴더는 다음과 같이 얻을 수 있다.

 

Scripting.FileSystemObject 객체 할당 및 해제

Scripting.FileSystemObject 객체는 컴퓨터(서버) 내 파일 시스템에 접근할 수 있는 메소드들을 제공하는 객체이다(출처: https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/filesystemobject-object).

<%
 Set fileSystemObject = Server.CreateObject("Scripting.FileSystemObject")
 ' ... '
 Set fileSystemObject = Nothing
 %>

 

GetFolder 메소드로 폴더에 대한 객체 얻기

[Scripting.FileSystemObject].GetFolder 메소드는 폴더를 특정하는 경로를 받아서 이에 대한 객체를 반환한다.

<%
 Set fileSystemObject = Server.CreateObject("Scripting.FileSystemObject")
 Set folder           = fileSystemObject.GetFolder(경로)
 ' ... '
 Set folder           = Nothing
 Set fileSystemObject = Nothing
 %>

 

이 때, 경로는 하드코딩도 되겠으나, Server.MapPath 메소드를 조합하면 다음과 같이 ASP 파일이 위치한 로컬 경로를 기준으로 한 상대 경로도 가능하다.

<%
 Set fileSystemObject = Server.CreateObject("Scripting.FileSystemObject")
 Set folder           = fileSystemObject.GetFolder(Server.MapPath("."))
 ' ... '
 Set folder           = Nothing
 Set fileSystemObject = Nothing
 %>

 

현재 지정된 폴더의 절대 경로 얻기

위와 같이 얻은 폴더 객체의 절대 경로는 다음과 같이 Path 프로퍼티로 구할 수 있다.

<%=folder.Path%>

 

현재 지정된 폴더 속 하위 폴더의 개수

위와 같이 얻은 폴더 객체에서 하위 폴더가 몇 개인지를 알기 위해 다음과 같이 SubFolders.Count 프로퍼티를 사용할 수 있다.

<%=folder.SubFolders.Count%>

 

현재 지정된 폴더 속 파일의 개수

위와 같이 얻은 폴더 객체에서 파일이 몇 개인지를 알기 위해 다음과 같이 SubFolders.Count 프로퍼티를 사용할 수 있다.

<%=folder.Files.Count%>

 

폴더 속 폴더를 하나씩 순회하기

SubFolders 프로퍼티는 그 자체가 Collection 객체이기도 하므로 다음과 같이 For Each 루프를 돌려서 하위 폴더들을 하나씩 순회할 수 있다.

<%
 Set fileSystemObject = Server.CreateObject("Scripting.FileSystemObject")
 Set folder           = fileSystemObject.GetFolder(Server.MapPath("."))
 
 For Each f in folder.SubFolders ' f is also Folder object
 	' ... '
 Next
 
 Set folder           = Nothing
 Set fileSystemObject = Nothing
 %>

 

폴더 속 파일을 하나씩 순회하기

마찬가지로 Files 프로퍼티도 그 자체가 Collection 객체이기도 하므로 다음과 같이 For Each 루프를 돌려서 폴더 속 파일들을 하나씩 순회할 수 있다.

<%
 Set fileSystemObject = Server.CreateObject("Scripting.FileSystemObject")
 Set folder           = fileSystemObject.GetFolder(Server.MapPath("."))
 
 For Each f in folder.Files ' f is File object
 	' ... '
 Next
 
 Set folder           = Nothing
 Set fileSystemObject = Nothing
 %>

 

서버 로컬 경로 내 파일 및 폴더 순회 예

다음은 asp 파일 자신이 위치한 폴더 내 파일과 하위 폴더들을 순회하여 클라이언트에게 보여주는 예이다.

<%@ language="VBScript" codepage="65001" %>
<%
 Session.CodePage = "65001"
 Response.ContentType = "text/html"
 Response.AddHeader "Content-Type", "text/html;charset=UTF-8"
 Response.Charset = "UTF-8"
 %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>codingCat.kr</title>
		<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
	</head>
	<body>
		<%
		 fileSystemPath = Server.MapPath(".")
		 
		 Dim fileSystemObject
		 Dim fileSystemFolder
		 
		 Set fileSystemObject = Server.CreateObject("Scripting.FileSystemObject")
		 Set fileSystemFolder = fileSystemObject.GetFolder(fileSystemPath)
		 %>
		<p>Local Path: <code><%=fileSystemFolder.Path%></code></p>
		<p>FOLDER(S): <code><%=fileSystemFolder.SubFolders.Count%></code> item(s).</p>
		<ul>
			<% For Each f in fileSystemFolder.SubFolders %><li>[<%=f.Name%>]</li><% Next %>
		</ul>
		<p>FILE(S): <code><%=fileSystemFolder.Files.Count%></code> item(s).</p>
		<ul>
			<% For Each f in fileSystemFolder.Files %><li><%=f.Name%></li><% Next %>
		</ul>
		<%
		 Set fileSystemFolder = Nothing
		 Set fileSystemObject = Nothing
		 %>
	</body>
</html>

카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
[Classic ASP] Charset, CodePage: 웹 페이지를 UTF-8 인코딩으로 내보내기
ASP(Classic ASP)에서 UTF-8 인코딩으로 웹 페이지를 내보내도록 다음과 같이 작성한다. * 참고: CodePage 65001과 UTF-8 인코딩은 같은 말이다(출처: https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers)
Common Gateway Interface/ASP & ASP.NET
2023. 3. 19. 08:16

[Classic ASP] Charset, CodePage: 웹 페이지를 UTF-8 인코딩으로 내보내기

Common Gateway Interface/ASP & ASP.NET
2023. 3. 19. 08:16

ASP(Classic ASP)에서 UTF-8 인코딩으로 웹 페이지를 내보내도록 다음과 같이 작성한다.

* 참고: CodePage 65001과 UTF-8 인코딩은 같은 말이다(출처: https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers)

<%@ language="VBScript" codepage="65001" %>
<%
 ' 세션에서 사용할 코드 페이지도 UTF-8(65001)로 세팅한다. '
 Session.CodePage = "65001"
 ' Response 객체에서 UTF-8 웹 페이지임을 세팅한다. '
 Response.ContentType = "text/html"
 Response.Charset = "UTF-8"
 ' HTTP 패킷 헤더 부분에서 이 페이지는 UTF-8(65001)로 인코드되었음을 세팅한다. '
 Response.AddHeader = "Content-Type", "text/html;charset=UTF-8"
 %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html> 
	<head> 
		<title> codingCat.kr</title> 
        <!-- HTML 파일 내 헤더에서도 UTF-8 인코딩임을 한 번 더 표시 -->
		<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
	</head> 
	<body> 
		<!-- HTML 본문 -->
	</body>
</html>

 

카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
썸네일 이미지
[Classic ASP] Server.MapPath : ASP 파일을 기준으로 한 로컬 경로 반환
Server.MapPath Server.MapPath(경로) 경로 로컬 상대경로 또는 URL 가상경로 * 반환값 * 상대경로 또는 URL 가상경로에 해당하는 서버 내(로컬) 절대경로를 반환 사용 예: asp 파일의 서버 내 로컬 경로를 얻기
Common Gateway Interface/ASP & ASP.NET
2023. 3. 18. 19:47

[Classic ASP] Server.MapPath : ASP 파일을 기준으로 한 로컬 경로 반환

Common Gateway Interface/ASP & ASP.NET
2023. 3. 18. 19:47

Server.MapPath

Server.MapPath(경로)
경로
로컬 상대경로 또는 URL 가상경로
* 반환값 *
상대경로 또는 URL 가상경로에 해당하는 서버 내(로컬) 절대경로를 반환

 

사용 예: asp 파일의 서버 내 로컬 경로를 얻기

<%@ language="VBScript" codepage="65001" %>
<%
 Session.CodePage = "65001"
 Response.ContentType = "text/html"
 Response.AddHeader "Content-Type", "text/html;charset=UTF-8"
 Response.Charset = "UTF-8"
 %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
	<head>
		<title>codingCat.kr</title>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	</head>
	<body>
		<% 'Finding the physical path to a file %>
		<p><%=Server.MapPath(".")%></p>
	</body>
</html>

카테고리 “Common Gateway Interface/ASP & ASP.NET”
more...
썸네일 이미지
[HTML5] HTML 내부에 PDF 파일 삽입하기
HTML 내부에 PDF 파일 삽입하기 html 문서에서 pdf 파일을 '링크(link)'하지 않고 '삽입(embed)'하는 방법에 대해 정리한다. embed 태그를 이용한 방법 embed 태그에 MIME type과 URI를 지정하면 HTML 내부에 pdf 파일이 삽입된다. 구 버전 HTML에서는 embed 태그에 pluginpage라는 속성(attribute)이 있어서 PC에 적절한 플러그인이 설치되어 있지 않은 경우 해당 플러그인을 설치할 수 있는 페이지로 연결시킬 수 있었지만 HTML5에서는 이 속성이 폐지(deprecated)되었다. 즉, 사용하면 안 된다. object 태그를 이용한 방법 그러나 stackoverflow에 따르면 embed보다는 object를 쓸 것을 권장하고 있다. embed 태..
Common Gateway Interface/HTML
2021. 2. 14. 15:10

[HTML5] HTML 내부에 PDF 파일 삽입하기

Common Gateway Interface/HTML
2021. 2. 14. 15:10

HTML 내부에 PDF 파일 삽입하기

html 문서에서 pdf 파일을 '링크(link)'하지 않고 '삽입(embed)'하는 방법에 대해 정리한다.

 

embed 태그를 이용한 방법

embed 태그에 MIME type과 URI를 지정하면 HTML 내부에 pdf 파일이 삽입된다. 구 버전 HTML에서는 embed 태그에 pluginpage라는 속성(attribute)이 있어서 PC에 적절한 플러그인이 설치되어 있지 않은 경우 해당 플러그인을 설치할 수 있는 페이지로 연결시킬 수 있었지만 HTML5에서는 이 속성이 폐지(deprecated)되었다. 즉, 사용하면 안 된다.

 

<embed type="application/pdf" src="{PDF}" width="{폭}" height="{높이}" />

Chrome에서 열어 본 결과
Microsoft Edge에서 열어 본 결과
Firefox에서 열어 본 결과

 

object 태그를 이용한 방법

그러나 stackoverflow에 따르면 embed보다는 object를 쓸 것을 권장하고 있다. embed 태그와 object 태그는 HTML5에서 둘 다 표준으로 인정되고 있지만, object 태그를 사용하면 현재 브라우저가 적절한 플러그인을 제공할 수 없다 하더라도 object 태그에 싸인 대체 콘텐츠가 렌더링될 수 있다고 한다. 또한 object 태그로 둘러싸인 콘텐츠는 서버에 요청(http-request)되는 기능을 갖고 있다고 한다. 요약하면, 브라우저가 적절한 플러그인을 제공할 수 없을 때에도 대체 콘텐츠가 온전하게 표시된다는 의미이다.

 

기본 형태

먼저 object 태그를 통해 다음과 같이 PDF 파일을 삽입할 수 있다. embed와 마찬가지로 MIME type과 URI를 지정하면 된다. 구 버전 HTML에서는 clsid라는 속성(attribute)으로 PC에서 특정 플러그인을 불러올 수 있고, 해당 플러그인이 없을 때는 codebase라는 속성(attribute)으로 그 플러그인을 다운로드할 주소를 지정했다. 다름아닌 ActiveX Control을 불러오는 기능이기에 HTML5에서는 이 속성이 폐지(deprecated)되었다. 즉 사용하면 안 된다.

 

<object type="application/pdf" data="{PDF}" width="{폭}" height="{높이}"></object>

 

실행 결과는 위에서 첨부한 캡처 화면과 동일하다.

 

대체 콘텐츠 삽입하기

대체 콘텐츠를 삽입하는 것은 어렵지 않다. object 태그 내부에 적고 싶은 내용을 적으면 된다.

 

<object type="application/pdf" data="{PDF}" width="{폭}" height="{높이}">
    <p>대체 콘텐츠입니다. 브라우저가 PDF 삽입을 지원하지 않거나 PDF 파일을 찾을 수 없습니다. <a href="{PDF}">직접 다운로드 해보기</a></p>
</object>

 

Chrome에서 열어 본 결과
Microsoft Edge에서 열어 본 결과
Firefox에서 열어 본 결과

 

호환성을 고려하여 같은 내용을 한번 더 적기

만일 대체 콘텐츠를 보이기 원치 않고 반드시 PDF가 삽입된 결과를 얻고자 하면 object 태그 안에 embed 태그로 같은 내용을 한 번 더 적어주면 된다. object 태그를 지원하지 않는 브라우저는 그 안에 담긴 embed 태그를 읽어서 PDF를 표시해 줄 것이다. 다만 HTML5의 기준에서 어차피 둘 다 표준이기 때문에 이렇게 적는 것이 그리 큰 의미가 있을지는 의문이다.

 

<object type="application/pdf" data="{PDF}" width="{폭}" height="{높이}">
    <embed type="application/pdf" src="{PDF}" width="{폭}" height="{높이}" />
</object>

 

툴바(toolbar) 가리기

위의 방법은 기본적으로 PDF 상단에 툴바가 나타난다.

Chrome에서 열어 본 결과
Microsoft Edge에서 열어 본 결과
Firefox에서 열어 본 결과

 

툴바를 없애려면 URI 끝에 toolbar=0 매개변수를 넣어주면 된다. embed, object 구분 없이 동일하며 다음 파일을 참고하면 여러가지 옵션들을 지정할 수 있다.

 

pdf_open_parameters.pdf
0.13MB

원본 위치: Parameters for Opening PDF Files

 

<object type="application/pdf" data="http://foo/bar.pdf#toolbar=0" width="{폭}" height="{높이}">
    <embed type="application/pdf" src="http://foo/bar.pdf#toolbar=0" width="{폭}" height="{높이}" />
</object>

 

여러 개의 옵션을 지정할 때는 &으로 결합하면 된다. 예를 들어 툴바를 없애고 페이지별 미리보기도 없애려면 toolbar=0&navpane=0과 같은 식으로 이을 수 있다.

단, 이 방법은 Firefox에서는 효과가 없는 듯하다...

 

Chrome에서 열어 본 결과
Microsoft Edge에서 열어 본 결과
Firefox에서 열어 본 결과

 

Base64 Data URI로 PDF 파일 지정하기

pdf 파일을 base64로 인코드(encode)하면 HTML 자체에 PDF 파일을 통째로 넣을 수 있다. 이 때의 주소는 data:application/pdf;base64,<내용>과 같이 지정한다.

단, Data URI에는 # 이후로 매개변수를 붙이는 표준이 없기 때문에 툴바를 없앤다거나 하는 옵션 지정은 불가하다.

 

<object type="application/pdf" data="data:application/pdf;base64,..." width="{폭}" height="{높이}">
    <embed type="application/pdf" src="data:application/pdf;base64,..." width="{폭}" height="{높이}" />
</object>

 

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

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

Common Gateway Interface/PHP
2018. 9. 10. 12:27

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 I. 쿠키를 사용한 로그인, 로그아웃 (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.php 소스 코드의 실행 화면

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

step2.phtml - 사용자 인증


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

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

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

# 로그인 승인 시 true, 아니면 false
$authorizeStatus = false;

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

# 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)
{
	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	# membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 이름을 기록한다.
	setcookie("membershipUsername", $trialUsername, time() + 12 * 60 * 60);

	# membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 암호를 기록한다.
	setcookie("membershipPassword", $trialPassword, time() + 12 * 60 * 60);
}
?>
<?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>
			<?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.phtml">3 단계(회원 페이지)</a> | </span>
				<span><a href="./step4.phtml">4 단계(로그아웃)</a></span>
			</p>
		</footer>
	</body>
</html>
[그림 2] step2.phtml 소스 코드의 실행 화면 (로그인 성공)
[그림 3] step2.phtml 소스 코드의 실행 화면 (로그인 실패)

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

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

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

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

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

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

step3.phtml - 회원 전용 페이지


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

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

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

# 로그인 승인 시 true, 아니면 false
$authorizeStatus = false;

# 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 ($_COOKIE["membershipUsername"] != null)
{
	# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	if ($_COOKIE["membershipPassword"] != null)
	{
		# 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$membershipUsername = $_COOKIE["membershipUsername"];
		$membershipPassword = $_COOKIE["membershipPassword"];

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

# 로그인 요청이 승인되었다면
if ($authorizeStatus)
{
	# 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간으로 연장한다.
	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함

	# membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 이름을 기록한다.
	setcookie("membershipUsername", $membershipUsername, time() + 12 * 60 * 60);


	# membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 암호를 기록한다.
	setcookie("membershipPassword", $membershipPassword, time() + 12 * 60 * 60);
}
?>
<?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><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>
[그림 5] step3.phtml 소스 코드의 실행 화면 (로그인 성공)
[그림 6] step3.phtml 소스 코드의 실행 화면 (로그인 실패)

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

step4.phtml - 로그아웃 화면


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

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

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

# 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 ($_COOKIE["membershipUsername"] != null)
{
	# 쿠키 변수 중에 membershipPassword이라는 데이터가 있는지 확인
	if ($_COOKIE["membershipPassword"] != null)
	{
		# 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$membershipUsername = $_COOKIE["membershipUsername"];
		$membershipPassword = $_COOKIE["membershipPassword"];
		$authorizeStatus = authorizeMembership
		(
			$membershipUsername,
			$membershipPassword
		);
	}
}

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

# membershipUsername이라 이름붙인 유효기간 만료된 쿠키변수에 
# 사용자 이름을 기록한다.
setcookie("membershipUsername", "<undefined>", time() - 12 * 60 * 60);


# membershipPassword이라 이름붙인 유효기간 만료된 쿠키변수에 
# 사용자 암호를 기록한다.
setcookie("membershipPassword", "<undefined>", time() - 12 * 60 * 60);
?>
<?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>
[그림 7] step4.phtml 소스 코드의 실행 화면 (로그아웃 성공)
[그림 8] step4.phtml 소스 코드의 실행 화면 (이미 로그아웃된 상태)

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

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

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


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

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

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

# 로그인 승인 시 true, 아니면 false
$authorizeStatus = false;

# authorizeMembership($trialUsername, $trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
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 ($_COOKIE["membershipUsername"] != null)
{
	// membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
	if ($_COOKIE["membershipPassword"] != null)
	{
		# 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$membershipUsername = $_COOKIE["membershipUsername"];
		$membershipPassword = $_COOKIE["membershipPassword"];

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

# 로그인 요청이 승인되었다면
if ($authorizeStatus)
{
	# 클라이언트의 쿠키 유효기간을 현재 시점으로부터 12시간으로 연장한다.
	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함

	# membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 이름을 기록한다.
	setcookie("membershipUsername", $membershipUsername, time() + 12 * 60 * 60);


	# membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 암호를 기록한다.
	setcookie("membershipPassword", $membershipPassword, time() + 12 * 60 * 60);
}
?>
<?php
################################################################################
# 웹 페이지 본문 영역
?>
<!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>
			<?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...
썸네일 이미지
Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完]
Perl 로그인 로그아웃 예제 정리 본 시리즈에서는 웹 개발을 할 때 자주 사용되는 기능인 로그인/로그아웃 기능에 대한 예제를 정리한다. 아이디와 암호가 일치할 경우 이 상태를 쿠키cookie나 세션session에 기억시키고, 이후 페이지 접속 시 해당 쿠키 또는 세션의 보유 여부에 따라 로그인한 이용자와 로그인하지 않은 이용자를 구분하고 서로 다른 페이지를 보여주도록 하는 것이 본 시리즈에서 구현하는 주된 기능이다. Perl 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) Perl 로그인 로그아웃 예제 정리 (part 02 - 세션을 사용한 예) [完] PHP 로그인 로그아웃 예제 정리 (part 01 - 쿠키를 사용한 예) PHP 로그인 로그아웃 예제 정리 (part 02 - 세션을..
Common Gateway Interface/Perl
2018. 8. 26. 17:25

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

Common Gateway Interface/Perl
2018. 8. 26. 17:25

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)


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

<Prologue>


CGI의 세션 기능을 사용하기 위해서는 CGI::Session 모듈을 설치해야 한다. 기본적으로 cpan install CGI::Session을 통해 설치할 수도 있지만 운영체제와의 원활한 연계를 위해 패키지 형태로 설치할 것이 권장된다.

RedHat 계열의 운영체제 (예: CentOS)는 터미널에서 다음의 명령을 실행한다.

$ sudo yum install perl-CGI-Session

Debian 계열의 운영체제 (예: Ubuntu)는 터미널에서 다음의 명령을 실행한다.

$ sudo apt install libcgi-session-perl

step1.cgi - 로그인 화면


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

#!/usr/bin/perl

use CGI qw/:standard/;

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

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

[그림 1] step1.cgi 소스 코드의 실행 화면

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

step2.cgi - 사용자 인증


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;
use CGI::Session;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

$trialUsername = undef;
$trialPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 서버에 저장된 세션 객체이다.
$objectSession = undef;
# 클라이언트로 전송할 쿠키이다.
$objectCookie = undef;

$authorizeStatus = 0;

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

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

# 로그인 요청이 승인되었다면
if ($authorizeStatus)
{
	# 세션 객체를 생성한다.
	$objectSession = new CGI::Session
	(
		"driver:File",
		undef,
		{Directory=>"/tmp"}
	);

	# membershipUsername이라 이름붙인 세션 변수에
	# 사용자 이름을 기록한다.
	$objectSession->param("membershipUsername", $trialUsername);

	# membershipPassword이라 이름붙인 세션 변수에
	# 사용자 암호를 기록한다.
	$objectSession->param("membershipPassword", $trialPassword);

	# 세션의 유효 기간은 현재 시점으로부터 12시간이다.
	$objectSession->expire("+12h");

	# 현재의 편집 상태를 세션으로 저장한다.
	$objectSession->flush();

	# 세션을 생성할 때 발급된 세션 ID를 CGISESSID라는 쿠키변수로써 클라이언트에 전달한다.
	# 여기에서는 쿠키의 유효 기간도 세션과 마찬가지로 12시간으로 정한다.
	$objectCookie = new CGI::Cookie
	(
		-name=>"CGISESSID",
		-value=>($objectSession->id),
		-expires=>"+12h"
	);

	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	print "Set-Cookie: ", $objectCookie->as_string, "\n";
}

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>2 단계 : 사용자 인증</title>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>2 단계 : 사용자 인증</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 승인 되었다면...
	print "<p>로그인에 성공했습니다.</p>";
	print "<p>쿠키 문자열</p>";
	print "<pre><code>", $objectCookie->as_string, "</code></pre>";
	print "<p><a href='./step3.cgi'>회원 페이지</a></p>";
}
else
{
	# 로그인 거부 되었다면...
	print "<p>로그인에 실패했습니다.</p>";
	print "<p><a href='./step1.cgi'>로그인 화면</a></p>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<span><a href='./step1.cgi'>1 단계(로그인)</a> | </span>";
print "<span><strong>2 단계(사용자 인증)</strong> | </span>";
print "<span><a href='./step3.cgi'>3 단계(회원 페이지)</a> | </span>";
print "<span><a href='./step4.cgi'>4 단계(로그아웃)</a></span>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

[그림 2] step2.cgi 소스 코드의 실행 화면 (로그인 성공)

[그림 3] step2.cgi 소스 코드의 실행 화면 (로그인 실패)

로그인이 정상적이라면 서버의 특정 경로에 세션에 대한 데이터가 생성되어있음을 확인할 수 있다. CentOS를 기준으로 /tmp/systemd-private-...-httpd.service-.../<디렉터리명>이다. 여기서 <디렉터리명>란 perl 코드에서 세션 객체를 생성할 때 { Directory=> "..." }로 지정한 이름이다. 세션이 유지되는 동안 root 권한으로 이 디렉터리를 들어가면 cgisess_<세션식별번호>라는 이름의 텍스트 파일이 아래와 같이 존재할 것이다.

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

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

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

step3.cgi - 회원 전용 페이지


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;
use CGI::Session;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 세션에 저장된 사용자 이름 및 암호를 읽어온다.

$membershipUsername = undef;
$membershipPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 서버에 저장된 세션 객체이다.
$objectSession = undef;
# 클라이언트로 전송할 쿠키이다.
$objectCookie = undef;
# 본 페이지로 전달된 쿠키를 확인한다.
%objectCookies = fetch CGI::Cookie;

$authorizeStatus = 0;

# 쿠키가 존재하면
# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (%objectCookies ne undef)
{
	# 쿠키 변수 중에 CGISESSID라는 데이터가 있는지 확인
	if ($objectCookies{"CGISESSID"} ne undef)
	{
		# 세션 객체를 생성한다.
		$objectSession = new CGI::Session
		(
			undef,
			(scalar $objectCookies{"CGISESSID"}->value),
			{Directory=>"/tmp"}
		);

		# 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
		if ($objectSession->param("membershipUsername") ne undef)
		{
			# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
			if ($objectSession->param("membershipPassword") ne undef)
			{
				# 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
				$membershipUsername = $objectSession->param("membershipUsername");
				$membershipPassword = $objectSession->param("membershipPassword");

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

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

	# membershipPassword이라 이름붙인 세션 변수에
	# 사용자 암호를 기록한다.
	$objectSession->param("membershipPassword", $membershipPassword);

	# 세션의 유효 기간은 현재 시점으로부터 12시간이다.
	$objectSession->expire("+12h");

	# 현재의 편집 상태를 세션으로 저장한다.
	$objectSession->flush();
	
	# 세션을 생성할 때 발급된 세션 ID를 CGISESSID라는 쿠키 변수로써 클라이언트에 전달한다.
	# 여기에서는 쿠키의 유효 기간도 세션과 마찬가지로 12시간으로 정한다.
	$objectCookie = new CGI::Cookie
	(
		-name=>"CGISESSID",
		-value=>($objectSession->id),
		-expires=>"+12h"
	);

	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	print "Set-Cookie: ", $objectCookie->as_string, "\n";
}

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>3 단계 : 회원 페이지</title>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>3 단계 : 회원 페이지</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 승인 되었다면...
	print "<p>회원 전용 페이지</p>";
	print "<p>환영합니다. $membershipUsername 님.</p>";
	print "<p>쿠키 문자열 :</p>";
	print "<pre><code>$ENV{'HTTP_COOKIE'}</code></pre>";
	print "<p><a href='./step4.cgi'>로그아웃</a></p>";
}
else
{
	# 로그인 거부 되었다면...
	print "<p>이 페이지를 보려면 로그인이 필요합니다.</p>";
	print "<p><a href='./step1.cgi'>로그인</a></p>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<span><a href='./step1.cgi'>1 단계(로그인)</a> | </span>";
print "<span><strong>2 단계(사용자 인증)</strong> | </span>";
print "<span><a href='./step3.cgi'>3 단계(회원 페이지)</a> | </span>";
print "<span><a href='./step4.cgi'>4 단계(로그아웃)</a></span>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

 

[그림 6] step3.cgi 소스 코드의 실행 화면 (로그인 성공)

 

[그림 7] step3.cgi 소스 코드의 실행 화면 (로그인 실패)

step4.cgi - 로그아웃 화면


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;
use CGI::Session;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 클라이언트의 쿠키로부터 전송된 사용자 이름 및 암호를 읽어온다.

$membershipUsername = undef;
$membershipPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 서버에 저장된 세션 객체이다.
$objectSession = undef;
# 클라이언트로 전송할 쿠키이다.
$objectCookie = undef;
# 본 페이지로 전달된 쿠키를 확인한다.
%objectCookies = fetch CGI::Cookie;

$authorizeStatus = 0;

# 쿠키가 존재하면
# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (%objectCookies ne undef)
{
	# 쿠키 변수 중에 CGISESSID라는 데이터가 있는지 확인
	if ($objectCookies{"CGISESSID"} ne undef)
	{
		# 세션 객체를 생성한다.
		$objectSession = new CGI::Session
		(
			undef,
			(scalar $objectCookies{"CGISESSID"}->value),
			{Directory=>"/tmp"}
		);

		# 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
		if ($objectSession->param("membershipUsername") ne undef)
		{
			# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인
			if ($objectSession->param("membershipPassword") ne undef)
			{
				# 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
				$membershipUsername = $objectSession->param("membershipUsername");
				$membershipPassword = $objectSession->param("membershipPassword");

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

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

# membershipUsername이라 이름붙인 세션 변수에
# 사용자 이름을 기록한다.
$objectSession->param("membershipUsername", "<undefined>");

# membershipPassword이라 이름붙인 세션 변수에
# 사용자 암호를 기록한다.
$objectSession->param("membershipPassword", "<undefined>");

# 세션 객체를 삭제함
$objectSession->delete();

# 클라이언트에도 이미 삭제된 세션 ID가 남아있지 않도록 쿠키를 강제 만료
$objectCookie = new CGI::Cookie
(
	-name=>"CGISESSID",
	-value=>"under",
	-expires=>"-12h"
);

# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
print "Set-Cookie: ", $objectCookie->as_string, "\n";

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>4 단계 : 로그아웃</title>";
print "<style>a { color: #0000FF; }</style>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>4 단계 : 로그아웃</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 된 상태였다면...
	print "<p>로그아웃되었습니다.</p>";
	print "<p><a href='./step1.cgi'>로그인</a></p>";
}
else
{
	# 로그인 안 된 상태였다면...
	print "<p>로그인되어있지 않습니다.</p>";
	print "<p><a href='./step1.cgi'>로그인</a></p>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<a href='./step1.cgi'>1 단계(로그인)</a> |";
print "<a href='./step2.cgi'>2 단계(사용자 인증)</a> | ";
print "<a href='./step3.cgi'>3 단계(회원 페이지)</a> | ";
print "<strong>4 단계(로그아웃)</string>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

[그림 8] step4.cgi 소스 코드의 실행 화면 (로그아웃 성공)

[그림 9] step4.cgi 소스 코드의 실행 화면 (이미 로그아웃된 상태)

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

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

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


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 세션에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

$membershipUsername = undef;
$membershipPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 본 페이지로 전달된 쿠키를 확인한다.
%objectCookies = fetch CGI::Cookie;

# 쿠키가 존재하면
# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (%objectCookies ne undef)
{
	# 쿠키 변수 중 CGISESSID라는 데이터가 있는지 확인
	if ($objectCookies{"CGISESSID"} ne undef)
	{
		# CGISESSID가 있으면 세션 객체를 불러온다.
		$objectSession = new CGI::Session
		(
			undef,
			(scalar $objectCookies{"CGISESSID"}->value),
			{Directory=>"/tmp"}
		);

		# 세션 변수 중 membershipUsername이라는 데이터가 있는지 확인
		if ($objectSession->param("membershipUsername") ne undef)
		{
			# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
			if ($objectSession->param("membershipPassword") ne undef)
			{
				# 세션 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
				$membershipUsername = $objectSession->param("membershipUsername");
				$membershipPassword = $objectSession->param("membershipPassword");

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

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

	# membershipPassword이라 이름붙인 세션 변수에
	# 사용자 암호를 기록한다.
	$objectSession->param("membershipPassword", $membershipPassword);

	# 세션의 유효 기간은 현재 시점으로부터 12시간이다.
	$objectSession->expire("+12h");

	# 현재의 편집 상태를 세션으로 저장한다.
	$objectSession->flush();

	# 세션을 생성할 때 발급된 세션 ID를 CGISESSID라는 쿠키 변수로써 클라이언트에 전달한다.
	# 여기에서는 쿠키의 유효 기간도 세션과 마찬가지로 12시간으로 정한다.
	$objectCookie = new CGI::Cookie
	(
		-name=>"CGISESSID",
		-value=>($objectSession->id),
		-expires=>"+12h"
	);

	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	print "Set-Cookie: ", $objectCookie->as_string, "\n";
}

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>1 단계 : 로그인</title>";
print "<style>a { color: #0000FF; }</style>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>1 단계 : 로그인</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 승인 되었다면...
	print "<p>이미 로그인되어 있습니다.</p>";
	print "<p><a href='step3.cgi'>회원 페이지</a></p>";
}
else
{
	# 로그인 거부 되었다면...
	print "<p>사용자 이름과 사용자 암호를 입력하세요.</p>";
	print "<form action='./step2.cgi' method='post'>";
	print "<label for='trialUsername'>사용자 이름 : </label><input type='text' id='trialUsername' name='trialUsername' />";
	print "<label for='trialPassword'>사용자 암호 : </label><input type='password' id='trialPassword' name='trialPassword' />";
	print "<input type='submit' />";
	print "</form>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<span><a href='./step1.cgi'>1 단계(로그인)</a> | </span>";
print "<span><strong>2 단계(사용자 인증)</strong> | </span>";
print "<span><a href='./step3.cgi'>3 단계(회원 페이지)</a> | </span>";
print "<span><a href='./step4.cgi'>4 단계(로그아웃)</a></span>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

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

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

Common Gateway Interface/Perl
2018. 8. 23. 13:19

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)


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

step1.cgi - 로그인 화면


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

#!/usr/bin/perl

use CGI qw/:standard/;

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

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

[그림 1] step1.cgi 소스 코드의 실행 화면

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

step2.cgi - 사용자 인증


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 이전 페이지에서 POST 방식으로 전송된 사용자 이름 및 암호를 읽어온다.

$trialUsername = undef;
$trialPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 클라이언트로 전송할 쿠키이다.
$objectUsername = undef;
# 클라이언트로 전송할 쿠키이다.
$objectPassword = undef;

# POST 방식으로 전달된 데이터 중 trialUsername이라는 데이터가 있는지 확인
if ($objectCGI->param("trialUsername") ne undef)
{

	# trialUsername이 존재하면, trialPassword라는 데이터도 있는지 확인 
	if ($objectCGI->param("trialPassword") ne undef)
	{
		# POST 데이터에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
		$trialUsername = $objectCGI->param("trialUsername");
		$trialPassword = $objectCGI->param("trialPassword");

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

# 로그인 요청이 승인되었다면
if ($authorizeStatus)
{
	# membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 이름을 기록한다.
	$objectUsername = new CGI::Cookie
	(
		-name=>"membershipUsername",
		-value=>$trialUsername,
		-expires=>"+12h"
	);

	# membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 암호를 기록한다.
	$objectPassword = new CGI::Cookie
	(
		-name=>"membershipPassword",
		-value=>$trialPassword,
		-expires=>"+12h"
	);

	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	print "Set-Cookie: ", $objectUsername->as_string, "\n";
	print "Set-Cookie: ", $objectPassword->as_string, "\n";
}

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>2 단계 : 사용자 인증</title>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>2 단계 : 사용자 인증</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 승인 되었다면...
	print "<p>로그인에 성공했습니다.</p>";
	print "<p>쿠키 문자열</p>";
	print "<pre><code>", $objectUsername->as_string, "</code></pre>";
	print "<pre><code>", $objectPassword->as_string, "</code></pre>";
	print "<p><a href='./step3.cgi'>회원 페이지</a></p>";
}
else
{
	# 로그인 거부 되었다면...
	print "<p>로그인에 실패했습니다.</p>";
	print "<p><a href='./step1.cgi'>로그인 화면</a></p>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<span><a href='./step1.cgi'>1 단계(로그인)</a> | </span>";
print "<span><strong>2 단계(사용자 인증)</strong> | </span>";
print "<span><a href='./step3.cgi'>3 단계(회원 페이지)</a> | </span>";
print "<span><a href='./step4.cgi'>4 단계(로그아웃)</a></span>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

[그림 2] step2.cgi 소스 코드의 실행 화면 (로그인 성공)

[그림 3] step2.cgi 소스 코드의 실행 화면 (로그인 실패)

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

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

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

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

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

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

step3.cgi - 회원 전용 페이지


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 클라이언트의 쿠키로부터 전송된 사용자 이름 및 암호를 읽어온다.

$membershipUsername = undef;
$membershipPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 본 페이지로 전달된 쿠키를 확인한다.
%objectCookies = fetch CGI::Cookie;

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

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

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

	# membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 이름을 기록한다.
	$objectUsername = new CGI::Cookie
	(
		-name=>"membershipUsername",
		-value=>$membershipUsername,
		-expires=>"+12h"
	);

	# membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 암호를 기록한다.
	$objectPassword = new CGI::Cookie
	(
		-name=>"membershipPassword",
		-value=>$membershipPassword,
		-expires=>"+12h"
	);

	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	print "Set-Cookie: ", $objectUsername->as_string, "\n";
	print "Set-Cookie: ", $objectPassword->as_string, "\n";
}

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>3 단계 : 회원 페이지</title>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>3 단계 : 회원 페이지</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 승인 되었다면...
	print "<p>회원 전용 페이지</p>";
	print "<p>환영합니다. $membershipUsername 님.</p>";
	print "<p>쿠키 문자열 :</p>";
	print "<pre><code>$ENV{'HTTP_COOKIE'}</code></pre>";
	print "<p><a href='./step4.cgi'>로그아웃</a></p>";
}
else
{
	# 로그인 거부 되었다면...
	print "<p>이 페이지를 보려면 로그인이 필요합니다.</p>";
	print "<p><a href='./step1.cgi'>로그인</a></p>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<span><a href='./step1.cgi'>1 단계(로그인)</a> | </span>";
print "<span><a href='./step2.cgi'>2 단계(사용자 인증)</a> | </span>";
print "<span><strong>3 단계(회원 페이지)</strong> | </span>";
print "<span><a href='./step4.cgi'>4 단계(로그아웃)</a></span>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

[그림 5] step3.cgi 소스 코드의 실행 화면 (로그인 성공)

[그림 6] step3.cgi 소스 코드의 실행 화면 (로그인 실패)

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

[그림 7] step3.cgi 소스 코드의 실행 결과 유효기간이 연장된 쿠키

step4.cgi - 로그아웃 화면


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 클라이언트의 쿠키로부터 전송된 사용자 이름 및 암호를 읽어온다.

$membershipUsername = undef;
$membershipPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 본 페이지로 전달된 쿠키를 확인한다.
%objectCookies = fetch CGI::Cookie;

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

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

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

# membershipUsername이라 이름붙인 유효기간 만료된 쿠키변수에 
# 사용자 이름을 기록한다.
$objectUsername = new CGI::Cookie
(
	-name=>"membershipUsername",
	-value=>"<undefined>",
	-expires=>"-12h"
);

# membershipPassword이라 이름붙인 유효기간 만료된 쿠키변수에 
# 사용자 암호를 기록한다.
$objectPassword = new CGI::Cookie
(
	-name=>"membershipPassword",
	-value=>"<undefined>",
	-expires=>"-12h"
);

# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
print "Set-Cookie: ", $objectUsername->as_string, "\n";
print "Set-Cookie: ", $objectPassword->as_string, "\n";

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>4 단계 : 로그아웃</title>";
print "<style>a { color: #0000FF; }</style>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>4 단계 : 로그아웃</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 된 상태였다면...
	print "<p>로그아웃되었습니다.</p>";
	print "<p><a href='./step1.cgi'>로그인</a></p>";
}
else
{
	# 로그인 안 된 상태였다면...
	print "<p>로그인되어있지 않습니다.</p>";
	print "<p><a href='./step1.cgi'>로그인</a></p>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<a href='./step1.cgi'>1 단계(로그인)</a> |";
print "<a href='./step2.cgi'>2 단계(사용자 인증)</a> | ";
print "<a href='./step3.cgi'>3 단계(회원 페이지)</a> | ";
print "<strong>4 단계(로그아웃)</string>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

[그림 8] step4.cgi 소스 코드의 실행 화면 (로그아웃 성공)

[그림 9] step4.cgi 소스 코드의 실행 화면 (이미 로그아웃된 상태)

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

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

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


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

#!/usr/bin/perl

use CGI qw/:standard/;
use CGI::Cookie;

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

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

# 로그인 승인 시 nonzero, 아니면 zero
my $authorizeStatus = 0;

# authorizeMembership(-trialUsername, -trialPassword)
# 사용자 이름과 암호를 비교하여 로그인 승인 여부를 결정하는 서브루틴.
# -trialUsername : 로그인을 시도하는 사용자 이름
# -trialPassword : 로그인을 시도하는 사용자가 입력한 암호
# 로그인 승인하면 nonzero를 반환하고 승인 거부 시 zero를 반환한다.
sub authorizeMembership(@)
{
	my %args = @_;
	my $trialUsername = $args{"-trialUsername"};
	my $trialPassword = $args{"-trialPassword"};

	# 로그인 요청하는 사용자 이름이 미리 지정된 이름과 같은지 검사
	if ($trialUsername eq $authorizedUsername)
	{
		# 이름이 일치하면, 암호가 같은지 검사
		if ($trialPassword eq $authorizedPassword)
		{
			# 이름과 암호가 모두 일치하면 로그인 승인
			return 1;
		}
	}

	# 그렇지 않을 경우 로그인 거부
	return 0;
}

################################################################################
# 웹 페이지 헤더 영역
# 세션에 기록된 사용자 이름 및 암호를 읽어와서 로그인 유효성을 검증한다.

$membershipUsername = undef;
$membershipPassword = undef;

# CGI 객체를 생성한다.
$objectCGI = new CGI;
# 본 페이지로 전달된 쿠키를 확인한다.
%objectCookies = fetch CGI::Cookie;

# 쿠키가 존재하면
# 로그인 유효성 검사 : 클라이언트의 쿠키가 본 페이지에 전달한 로그인 정보를 검증한다.
if (%objectCookies ne undef)
{
	# 쿠키 변수 중 membershipUsername이라는 데이터가 있는지 확인
	if ($objectCookies{"membershipUsername"} ne undef)
	{
		# membershipUsername이 존재하면, membershipPassword라는 데이터도 있는지 확인 
		if ($objectCookies{"membershipPassword"} ne undef)
		{
			# 쿠키 변수에서 얻은 사용자 이름과 암호로 로그인 상태가 유효한지 검증
			$membershipUsername = $objectCookies{"membershipUsername"}->value;
			$membershipPassword = $objectCookies{"membershipPassword"}->value;
			
			# membershipUsername과 membershipPassword가 모두 수신되면,
			# 앞서 정의된 authorizeMembership 메서드로 로그인 요청한다.
			$authorizeStatus = authorizeMembership
			(
				-trialUsername=>$membershipUsername,
				-trialPassword=>$membershipPassword
			);
		}
	}
}

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

	# membershipUsername이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 이름을 기록한다.
	$objectUsername = new CGI::Cookie
	(
		-name=>"membershipUsername",
		-value=>$membershipUsername,
		-expires=>"+12h"
	);

	# membershipPassword이라 이름붙인 유효기간 12시간짜리 쿠키 변수에 
	# 사용자 암호를 기록한다.
	$objectPassword = new CGI::Cookie
	(
		-name=>"membershipPassword",
		-value=>$membershipPassword,
		-expires=>"+12h"
	);

	# 쿠키는 HTTP 헤더 부분에 명시되어야 하므로 웹 페이지의 본문에 앞서 이를 출력함
	print "Set-Cookie: ", $objectUsername->as_string, "\n";
	print "Set-Cookie: ", $objectPassword->as_string, "\n";
}

print "Content-type: text/html; charset=UTF-8\n\n";

################################################################################
# 웹 페이지 본문 영역

print "<!DOCTYPE html>";
print "<html lang='ko'>";
print "<head>";
print "<meta charset='UTF-8' />";
print "<title>1 단계 : 로그인</title>";
print "<style>a { color: #0000FF; }</style>";
print "</head>";
print "<body>";
print "<header>";
print "<h1>1 단계 : 로그인</h1>";
print "</header>";
print "<hr />";
print "<section>";
if ($authorizeStatus)
{
	# 로그인 승인 되었다면...
	print "<p>이미 로그인되어 있습니다.</p>";
	print "<p><a href='step3.cgi'>회원 페이지</a></p>";
}
else
{
	# 로그인 거부 되었다면...
	print "<p>사용자 이름과 사용자 암호를 입력하세요.</p>";
	print "<form action='./step2.cgi' method='post'>";
	print "<label for='trialUsername'>사용자 이름 : </label><input type='text' id='trialUsername' name='trialUsername' />";
	print "<label for='trialPassword'>사용자 암호 : </label><input type='password' id='trialPassword' name='trialPassword' />";
	print "<input type='submit' />";
	print "</form>";
}
print "</section>";
print "<hr />";
print "<footer>";
print "<p>";
print "<span><strong>1 단계(로그인)</strong> | </span>";
print "<span><a href='./step2.cgi'>2 단계(사용자 인증)</a> | </span>";
print "<span><a href='./step3.cgi'>3 단계(회원 페이지)</a> | </span>";
print "<span><a href='./step4.cgi'>4 단계(로그아웃)</a></span>";
print "</p>";
print "</footer>";
print "</body>";
print "</html>";

[그림 11] 로그인이 유효한 상태에서 접속하였을 때, step1.cgi 소스 코드의 출력 결과
카테고리 “Common Gateway Interface/Perl”
more...

“Common Gateway Interface” (14건)