관리 메뉴

새로운 시작, GuyV's lIfe sTyle.

닷넷 게시판 만들기 Part 35 - 로그인, 로그아웃 전략 본문

ⓟrogramming/asp.net 게시판

닷넷 게시판 만들기 Part 35 - 로그인, 로그아웃 전략

가이브 2011. 5. 23. 17:32

2011/05/13 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 31
2011/05/16 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 32
2011/05/18 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 33
2011/05/19 - [ⓟrogramming/asp.net 게시판] - 닷넷 게시판 만들기 Part 34


1. 닷넷 개발환경 준비, 테스트
2. 닷넷 알아보기 [7/7]
3. asp.net 컨트롤 [10/10]
4. 데이터베이스(DB) [7/7]
5. 닷넷 게시판을 만들어보기 전에.. [4/4]
6. 게시판 만들기 [5/..]


회원 가입 처리를 완료하였으니 이제 회원 가입을 완료한 사람이 자신의 ID와 비밀번호로 로그인을 할 수 있는 기능을 구현해보자.

강의 초반에 작성된 index.aspx 파일의 주석문을 보신 분은 아시겠지만 로그인을 만들려고 지정한 구간이 이미 존재한다. 물론 필자 마음대로 했기 때문에 여러분은 나름대로 생각하셔서 괜찮은 위치에 하도록 하자.

index.aspx는 공통 영역을 위해 top/bottom.ascx 파일 2개로 나누어 놓았다. top.ascx 파일이 상단의 공통 페이지인데, 여기에 로그인/로그오프를 하기 위해 <div>태그로 두 개의 구역을 미리 만들어 놓았다.

<div>태그는 일반적으로 구역을 나누기 위해 존재한다. 어떤 큰 덩어리라고 생각하면 되겠다. 메인메뉴/서브메뉴/내용의상단/내용... 등등 이렇게 큰 틀을 잡는 용도로 쓰는 태그라고 보면 되겠다. 혹시 해보신 다뤄보신 분은 아시겠지만 닷넷의 웹폼 컨트롤 중 Panel 컨트롤이 이 <div>태그로 렌더링된다. 

어쨌든, 우리가 가지고 있는 top.ascx 파일의 제일 하단에 보면

<div id="login_start">
..
</div>

<div>태그 하나와 그 밑에,

<div id="login_done">
..
</div>


이렇게 존재할 것이다. 직관적으로 <div>태그의 ID가 login_start 인 곳에 로그인 폼(ID,비밀번호입력,버튼)을 배치하면 될 것 같고, login_done 에 로그인 된 후에 나오는 메시지와 로그아웃 버튼을 만들어서 처리하면 될 것 같다.

로그인부터 구성해보자. 필자는 다음과 같이 구성했다.

<!-- 로그인 폼 시작 -->
<div id="login_start" runat="server" style="background-color:#eeddff"> 

<form action="login_proc.aspx" method="post" style="display:inline; margin:0">

 <font color="blue">[로그인]</font>
 ID : <input type="text" id="user_id" name="user_id" size="10">
 PW : <input type="password" id="user_pw" name="user_pw" size="10">
 <input type="submit" value="로그인">


</form>

</div>
<!-- 로그인 끝 -->


(태그의 "style"속성은 프로그래밍 코드와 관련없는 디자인 관련 요소이니 무시하도록 하자)

로그인 폼은 runat="server" 를 붙여주지 않고 그냥 login_proc.aspx 파일에서 처리하도록 한다. 그렇기 때문에 ID,PW 텍스트 박스 역시 웹폼이 아닌 HTML 태그형식으로 구성한다. 버튼도 마찬가지로 type="submit"으로 해주어 Button 웹폼을 대체한다.

이렇게 서버컨트롤 <form>으로 구성하지 않는 이유는, aspx 페이지에서는 <form runat="server"> 태그를 한 페이지에 1개만 배치할 수 있기 때문이다. 이전에 만들어 놓은 회원가입 페이지(member_join.aspx)는 <form runat="server">로 구성을 했는데, 만약 top.ascx에 로그인도 구성을 하면 다음처럼 오류가 발생하게 된다.

이러한 문제를 피하기 위해서 로그인 처리하는 폼은 그냥 일반 HTML형식으로 만드는 것이다.

다시 작성된 소스로 돌아와서, 우리가 예전에 다루었던 순수 HTML의 폼을 처리하는 방법에서, 실제 <form>..</form>에서 항목의 이름으로 사용되는 것은 "name"속성이라고 했었다. id는 (우리가 다루지 않고 있지만) 클라이언트 스크립트 언어인 '자바스크립트'라는 녀석이나 디자인을 구성하는 CSS에서 사용하는 녀석이다. (서버컨트롤은 자동으로 id와 name 두 개 모두 렌더링될 때 붙게되는 것을 알 수 있다.)

해서 사실 id를 붙일 필요는 없으나, 버릇으로 붙여주기로 하고 name과는 중복되어도 상관없으며 실제 <form action=""> 에 지정된 폼 값을 받는 페이지에서는 Request.Form["name속성"] 으로 읽어야 한다. (역시 강의 초반에 다 해봤던 것들 아닌가?)

그리고 로그인 폼을 감싸고 있는 <div>에 runat="server"를 붙였음에 주목하자.
로그인이 되어 있지 않을 때는 "로그인 된 화면"인 login_done 을 숨겨줄 것이다. 그리고 로그인이 완료되면 로그인 폼(id=login_start)을 숨기고 로그오프 <div>태그를 보여줘야 할 것이다.

다음은 로그인이 된 것을 보여질 <div> 내용이다.

<!-- 로그인 된 화면 -->
<div id="login_done" runat="server" style="background-color:#eeddff" visible="false">

<form action="logout.aspx" style="display:inline; margin:0">

어서오세요! "누구누구"님. 반갑습니다.
<input type="submit" value="로그아웃">

</form>

</div>
<!-- 로그인 된 화면 끝 -->




<div> 태그에 하드코딩으로 visible="false" 속성을 주었다. <div>태그에 runat="server"를 붙여서 서버컨트롤로 만들었기 때문에 visible 속성을 줄 수 있는 것임을 일고 있으리라 생각한다. 닷넷 서버컨트롤은 모두 Controls 를 상속받고 있기 때문에 Visible 같은 녀석은 모두 사용가능하다.

그리고 <form>..</form> 태그 역시 로그인과 마찬가지로 runat="server"를 주지 않고 HTML 폼으로 구성하며, 로그아웃 버튼 달랑 하나를 배치한다. 이는 logout.aspx 파일로 아무런 값 없이 그냥 전송할 것이고 logout.aspx 파일에서는 단순하게 로그인 된 정보를 모두 날려버리면 그만이다.

이제 <div id="login_done">태그에 Visible 속성을 true로 주거나 잠깐 삭제하고 열어보면 다음처럼 두가지 조건의 화면이 다 잘 보일것이다.

다시 login_done 컨트롤 속성을 visible="false"로 주고 로그인만 보이게 하자.

로그인 기능에서, 로그인 버튼을 누르면 무조건 login_proc.aspx 페이지로 user_id, user_pw 이렇게 두 개의 값을 던질 것이다. 해서 login_proc.aspx 에서 프로그램 코드를 넣어 처리해야 한다.

5장에서 잠깐 '전역 변수'라는 것에 대해 말씀드렸었고, 이것은 사이트의 모든 페이지에서 사용할 수 있는 변수라고 했었다. 크게 Application 변수와 Session 변수로 나누어지고, 어플리케이션 변수는 사용자끼리도 값을 공유하는 반면, Session은 다른 사람이 건들 수 없는, 개인만 사용하는 전역 변수라고 했었다. 현재 웹사이트에 방문중인 사람의 수를 구할 수 있는 이유가 어플리케이션 변수라는 것이 있기 때문이다.

Session 변수의 간단한 사용법은 Session["변수명"] = "값"; 의 형식으로 컬렉션(Collection)에 값을 주듯이 사용하면 된다. 값이 할당되지 않으면 null 이다.
우리는 회원 로그인이 잘 되었다면 Session["login_id"] = "로그인한ID" 의 세션 변수를 할당해 주는 것으로 하자. 그리고 닉네임도 함께 Session["login_nick"] 의 이름으로 넣어주자. 이렇게 몇개의 자주 쓰는 정보를 세션에 할당해 놓으면 차후에 우리가 해당 회원의 닉네임을 알아내기 위해 DB입출력이 더이상 일어나지 않는 장점이 있다. 

입력한 ID와 비밀번호를 DB에서 확인하기 위해 DB연동을 해야할 것이다. 쉽게 시작하기 위해 index.aspx 파일을 다른 이름으로 저장하여 login_proc.aspx 파일로 새로 저장하자. 그리고 불필요한 내용은 지우고, 페이지가 열리자 마자 처리를 해야 하기 때문에 Page_Load() 메서드를 구현하기로 한다. 물론 DB연동을 위해 네임스페이스 Study 를 Import 하는 것도 잊어서는 안될 것이다.


login_proc.aspx 페이지 첫 구성


<%@ Register TagPrefix="INCLUDE" TagName="TOP" src="top.ascx" %>
<%@ Register TagPrefix="INCLUDE" TagName="BOTTOM" src="bottom.ascx" %>
<%@ Import Namespace = "System.Data" %>
<%@ Import Namespace = "Study" %>

<script language="C#" runat="server">

 void Page_Load()
 {
 }

</script>


<INCLUDE:TOP
 runat="server" />

 

<!--------------------------- 여기서부터 내용 ------>
<div id="content">


<center>
[로그인처리결과]
<br>
<br>
<ASP:Label id="lblMessage" runat="server" forecolor="blue" />
</center>

 

</div>
<!-- 내용끝 ---------------------------------------->

 

<INCLUDE:BOTTOM
 runat="server" />



로그인 페이지에서는 간단하게 입력받은 ID/PW에 맞는 자료를 가져오도록 하자.
만약 결과가 없다면 당연히 회원의 정보는 DB에 없는 것이다. 있다면 각각의 값들을 우리가 미리 정해준 세션 값으로 넣어주면 되겠다. 앞으로 이제 회원만 접근해야 하는 페이지는 이 세션값이 null 인지 아닌지를 검사하여 튕겨내거나 허락시켜주면 되는 것이다. 매우 간단하다.

필자가 말한 내용을 구현하면 다음과 같다. Page_Load() 이벤트 메서드에서 모두 처리된다.

login_proc.aspx 로그인 처리

<script language="C#" runat="server">

 void Page_Load()
 {

  string id = Request.Form["user_id"];
  string pwd = Request.Form["user_pw"];
  string message = "";
  string query = String.Format("SELECT * FROM member WHERE user_id='{0}' AND user_password='{1}'", id, pwd);
  
  Database DB = new Database();  
  DataTable dtMember = DB.ExecuteQueryDataTable(query);

  // 자료 없음
  if (dtMember.Rows.Count == 0)
   message = "회원을 찾을 수 없습니다.";
  // 자료 있음
  else
  {
   // 세션변수 2개 할당
   Session["login_id"] = id;
   Session["login_nick"] = dtMember.Rows[0]["nickname"];

   message = String.Format("{0}({1}) 회원님. 로그인이 성공하였습니다~", Session["login_id"], Session["login_nick"]); 

  }

  // 명시적으로 인스턴스 소멸(생략가능)
  dtMember.Dispose();
  
  // 최종 메시지
  lblMessage.Text = message;


 }

</script>



넘어온 ID와 비밀번호를 변수에 각각 저장해두고, 메시지를 뿌리기 위한 message 변수를 하나 마련한다.

문자열 query 에 쿼리문을 잘 만들어 실행하는데, 닉네임(nickname 컬럼)을 가져오기 위해 2개 이상의 결과를 DataTable 로 넘겨주는 메서드, ExecuteQueryDataTable(string query) 를 사용한다. DataTable.Rows 가 결과의 행(Row 또는 Record)의 컬렉션이므로, Count 속성이 존재한다.
 
DataTable.Rows.Count 속성으로 넘어온 결과의 행이 몇 개인지 확인해서 0이라면 해당 ID/PW에 해당하는 자료는 없는 것이고, 있다면 로그인이 잘 되었으며 세션 변수를 각각 할당해주면 된다.

그리고 해당하는 결과 메시지를 lblMessage 에 지정해주면 완료.

위와 같은 그림처럼 이렇게 처리가 될 것이다.

로그인이 끝났으니 앞서 top.ascx 에서 만든 <div>태그 두 개를 로그인 성공했을 때 할당되는 세션값으로 조절해보자. top.ascx 파일을 열고, 소스의 맨 상단에 페이지가 열릴 때마다 처리할 수 있도록 Page_Load() 메서드를 선언하여 if() 문으로 <div> 두 개를 토글 시키자.

그리고 맨 하단에 있는 로그인 된 화면의 메시지로 출력할 [어서오세요! "누구누구"님. 반갑습니다.] 에서 "누구누구"를 실제 로그인한 사람의 닉네임 세션 값으로 대체하기 위해 Label 컨트롤로 바꾸어주자. 이 컨트롤의 id 는 lblNickname 으로 지정한다.

로그인/로그오프 상태에 따라 표시되게 top.ascx 수정

<script language="C#" runat="server">

 void Page_Load()
 {
  if (Session["login_id"] != null)
  {
   login_start.Visible = false;
   login_done.Visible = true;
   lblNickName.Text = (string)Session["login_nick"];
  }
 }
</script>


(... 중략 ...)



<!-- 로그인 된 화면 -->
<div id="login_done" runat="server" style="background-color:#eeddff" visible="false">
<form action="logout.aspx" style="display:inline; margin:0">
 어서오세요! <ASP:Label id="lblNickName" runat="server" /> 님. 반갑습니다.
 <input type="submit" value="로그아웃">
</form>
</div>
<!-- 로그인 된 화면 끝 -->

 



이제 우리가 만들고 있는 웹 사이트의 어떤 페이지에서도 로그인을 하게 되면 화면이 바뀌게 될 것이다. 이제 로그아웃 기능을 처리하는 logout.aspx 을 만들어보자.

로그아웃은 세션 변수인 Session["login_id"]와 Session["login_nick"] 값을 없애버리면 된다.

Session.Abandon() 메서드를 이용하면 깔끔하게 날려주게된다. 이 메서드는 SessionID 까지 모두 날려주니 상황에 맞게 잘 사용해야 한다. (필요에 의해 세션 변수를 이용하다가 부딪힐 날이 올 것이다. ^^)

logout.aspx 파일은 결과로는 단순하게 로그아웃 되었다는 고정 메시지를 뿌려주면 될 것 같고 프로그램 처리는 Page_Load() 에서 Session.Abandon() 메서드를 호출하면 되겠다. login_proc.aspx 파일을 다른이름으로 저장하여 필요없는 부분을 삭제하고 만들도록 하자.

logout.aspx 전체 소스


<%@ Register TagPrefix="INCLUDE" TagName="TOP" src="top.ascx" %>
<%@ Register TagPrefix="INCLUDE" TagName="BOTTOM" src="bottom.ascx" %>


<script language="C#" runat="server">

 void Page_Load()
 {
   Session.Abandon();
 }

</script>


<INCLUDE:TOP
 runat="server" />

 

<!--------------------------- 여기서부터 내용 ------>
<div id="content">


<center>

성공적으로 로그아웃 되었습니다!

</center>

 

</div>
<!-- 내용끝 ---------------------------------------->

 

<INCLUDE:BOTTOM
 runat="server" />




로그아웃 버튼을 눌러 잘 작동하는지 살펴보자.

아마 이상한 문제점을 발견할 수 있을 것이다. 로그아웃을 하고 나서 이동한 로그아웃 페이지에서는 상단에 아직 로그인 중이라는 메시지가 뜬다. 그리고 첫 페이지로 이동하고 나서야 로그인 폼이 보일 것이다.

그 이유는, top.ascx 이 먼저 처리되기 때문이다. 로그아웃 전(Session.Abandon() 호출하기 전)에 이미 <div>토글기능을 처리했기 때문에 변하지 않는데, 꽁수를 좀 부리면 간단하게 다음처럼 한번 더 logout.aspx 파일을 자동호출하여 처리할 수 있다.

수정된 logout.aspx


<script language="C#" runat="server">

 void Page_Load()
 {
   if (Session["login_id"] != null)
   {
         Session.Abandon();
       Response.Redirect("logout.aspx");
   }

 }

</script>



세션이 비어있지 않으면(logout.aspx가 첫 호출이면) 비운 후 한번 더 logout.aspx 페이지로 강제로 이동시킨다. 그러니까 처음 logout.aspx 에서는 세션을 비우게 되고, 다시 logout.aspx를 열게 되는데, 두번째 열 때는 세션이 null 이므로 if () 는 실행되지 않는 것이다. top.ascx를 다시 처리하기 위한 편법이라 할 수 있겠다. 이런 해결 방법은 필자의 생각일 뿐이고, 여러분들이 또 다른 더 좋은 방안을 생각해보기 바란다.

이렇게 로그인/로그아웃 처리를 함께 해보았다.
몇가지 중요한 것들이 빠져있긴 하다. login_proc.aspx 에서는 ID 또는 PW가 빈 값을 때 처리하는 코드, 회원가입때 처럼 ID가 4자 이하 또는 12자 초과일 때는 아예 체크를 하지 않고 오류를 발생하는 코드라던가 회원 정보를 수정하는 페이지도 빠져있다. 

하지만 이런 것들은 굳이 해보지 않아도 여러분들이 별 문제 없이 따라오셨다면 충분히 처리가능한 것들이다. 프로그래밍은 우리가 마음먹은대로 잘 되는 녀석이며, 처음에는 원래 생각처럼 잘 되지 않기 때문이다.

다음 첨부파일은 지금까지 진행한 전체 소스파일이다.
지면으로는 소스를 표현하기가 힘드니 잘 안될때는 다음의 첨부 파일을 활용하시길 바란다.

home_part5.zip



다음시간에...

반응형
Comments