17. ASP.NET 로그인 컨트롤과 회원 관리
ASP.NET에서 회원 관리를 어떻게 다루는지에 대한 내용을 공부합니다. 회원 가입, 로그인 및 로그인 정보 표시, 로그아웃 등을 구현해 보겠습니다.
1. ASP.NET 폼 인증과 로그인(Login) 컨트롤
회원제 사이트는 회원 인증 방식을 사용하여 회원과 비회원이 서로 다른 권한으로 사이트를 이용하게 합니다. ASP.NET은 폼 인증을 비롯한 많은 기술로 이러한 회원 관리를 처리합니다.
2. 회원 관리의 주요 범위
회원 관리는 주로 다음과 같은 기능으로 구현됩니다.
- 회원 가입(Register)
- 로그인(Login)
- 로그인 시도 횟수 제한(Lockout)
- 로그아웃(Logout)
- 회원 정보 보기/수정(Manage)
- 프로필 변경
- 암호 변경
- 회원 탈퇴
회원 관리 관련 주요 기능 이름
회원 관리와 관련된 주요 기능 이름은 다음과 같습니다.
- Login
- Profile
- Register
- Logout
3. 인증(Authentication)과 권한(Authorization)
**인증(Authentication)**은 사용자의 아이디와 암호를 통해 신원을 확인하는 과정으로, 로그인이 성공적으로 이루어졌음을 의미합니다. 권한(Authorization) 또는 허가는 인증된 사용자가 특정 자원에 접근할 수 있는 권리를 부여하는 것으로, 응용 프로그램 내에서 특정 권한에 대한 승인을 의미합니다. 혼동을 방지하기 위해, 책과 강의에서는 권한과 허가를 동일한 단어로 사용하겠습니다.
업무적 관점에서 인증과 권한은 다음과 같이 표현될 수 있습니다.
- 계정 관리(Authentication)
- 회원 관리
- 접근 통제(Authorization)
- 역할 관리
- 게시판 접근 허가(Permission)
- 인증된 사용자에게 특정 게시판(페이지)에 대한 사용 허가 부여
인증과 권한 요약
인증: Authentication
- 사용자의 신원을 확인하는 과정
- 애플리케이션에서 아이디와 암호가 필요(증거되는 자료 필요)
- 보호 기능 및 리소스에 대한 접근 제한
참고: Authentication 영어로: Validating who a user claims to be
권한(허가): Authorization
- 인증된 사용자의 특정 권한 결정(제한된 접근)
- 권한은 역할(Role)과 같은 다양한 요소를 기반으로 처리
- 최소 권한 원칙 적용
참고: Authorization 영어로: Giving someone permission to do or have something
17.4 인증 방식의 종류
ASP.NET에서 사용할 수 있는 인증 방식은 세션(Session) 인증, 쿠키(Cookie) 인증, 폼(Form) 인증, ASP.NET Identity 등 다양합니다.
- 세션 인증: ASP.NET의 Session 개체를 사용하여 인증된 사용자에 대한 특정 값을 비교하는 방식으로, 가장 고전적인 인증 방식입니다.
- 쿠키 인증: 서버 측 자원 사용을 줄이기 위해 인증 정보를 클라이언트 웹 브라우저의 쿠키에 저장하는 방식입니다.
- 폼 인증: ASP.NET 웹 폼의 대표적인 인증 방식으로, 인증 관련 기능이 API화되어 있습니다. ASP.NET Core에서는 사용되지 않습니다.
- ASP.NET Identity: ASP.NET 웹 폼과 MVC 등 최신 버전에서 사용하는 인증 방식 중 하나입니다. 이 책에서는 웹 폼과 MVC에서는 폼 인증을, ASP.NET Core에서는 쿠키 인증을 사용합니다. ASP.NET Web Forms에서는 ASP.NET Identity를 사용하지 않습니다. ASP.NET Identity에 관심이 있는 독자는 마이크로소프트 문서(Docs) 사이트를 참고하시기 바랍니다.
- IdentityServer: ASP.NET을 위한 OAuth와 OpenID Connect 구현을 위한 오픈소스 인증 프레임워크입니다. ASP.NET Core용으로는 IdentityServer4를 제공합니다.
17.4.1 참고: ASP.NET Identity
ASP.NET Identity는 마이크로소프트 ASP.NET 개발팀에서 만든 자동화된 회원 관리 기능입니다. 마이크로소프트는 오랜 시간 동안 다양한 시도를 통해 여러 가지 회원 관리 기능을 제공해왔습니다. 그러나 필자는 사용자가 직접 아이디와 비밀번호를 입력받아 인증을 구현하는 방법을 권장합니다. 실제 운영 시 커스터마이징이 어려워 관리가 더 어려울 수 있기 때문입니다. 이 책에서는 ASP.NET에서는 폼 인증을, ASP.NET Core에서는 쿠키 인증(세션)을 기본으로 사용합니다. 2020년 현재, ASP.NET Core Identity와 IdentityServer4에 대한 지원이 강화되어 SSO와 같은 기능을 구현하는 데 편리합니다.
17.4.2 참고: 아이핀
아이핀(i-PIN)은 웹 사이트에서 주민등록번호 대신 사용할 수 있는 사이버 신원 확인 번호로, 인터넷상에서 주민등록번호 유출과 도용을 막기 위해 만들어졌습니다. 이용 상의 불편과 연계 기능 보완을 위해 아이핀 2.0에서는 아이핀 통합 ID 관리 시스템을 구축하여 이용 절차를 2단계로 줄이고, 발급 과정에서 불필요한 동의 절차를 간소화했습니다. 그러나 필자는 이를 엄청난 세금 낭비라고 생각합니다.
17.5 폼 인증 방식의 종류
ASP.NET 웹 폼에서 사용하는 여러 인증 방식 중 주로 사용되는 방식은 다음과 같습니다. ASP.NET에서 웹 기반 회원 관리 기능을 구현할 때 "Forms"로 값을 설정하면 됩니다.
- Windows: Windows 운영체제에 로그인할 수 있는 사용자 계정을 말하며, 일반적으로 "Administrator"와 "IUSR_컴퓨터명" 계정을 의미합니다. ASP.NET에서 웹 사이트를 생성하면 Windows 인증을 기본으로 사용합니다.
- Forms: ASP.NET에서 주로 사용하는 인증 방식으로, 웹 사이트에서 로그인/로그아웃 과정을 거쳐 인증 쿠키를 제공하여 인증을 결정합니다. 이와 관련된 클래스를 제공해 쉽게 구현할 수 있으며, 이번 강의에서 배우는 로그인 컨트롤을 사용하면 코드 없이도 손쉽게 구현할 수 있습니다.
- None: 사용자 정의 인증 방식으로, 사용자가 직접 인증 방식을 만들어야 합니다. 주로 세션 인증 또는 쿠키 인증을 사용하여 세션 값 또는 쿠키 값이 있느냐에 따라 인증을 처리하고, 세션 값이 "Administrators"와 같은지를 비교해 권한을 부여합니다. 이 방식은 모든 내용을 사용자가 직접 코드로 구현해야 한다는 단점이 있습니다.
이와 같은 인증 방식 중 어떤 것을 사용할지에 따라 웹 인증 방식이 결정됩니다. Web.config 파일의 인증 모드에 다음 코드를 추가합니다.
<authentication mode="Forms">
</authentication>
17.6 ASP.NET 웹 폼 로그인 컨트롤
ASP.NET 로그인 컨트롤은 웹 사이트에서 사용자 관리를 간단히 구성할 수 있도록 도와줍니다. 회원 관리 관련 코드를 사용자가 직접 작성하지 않아도, 컨트롤만 잘 사용하면 간단한 회원 관리를 빠르게 구현할 수 있습니다. 하지만 ASP.NET 개발 팀에서 만들어놓은 고유 저장 테이블을 사용해야 하고, 커스터마이징이 어려워 이 책에서는 로그인 컨트롤보다는 코드 기반으로 직접 인증을 처리해봅니다.
17.6.1 Login 컨트롤
로그인 컨트롤은 아이디와 암호를 입력받고, 로그인을 할 수 있는 폼을 자동으로 생성해주는 컨트롤입니다.
17.6.2 LoginView 컨트롤
로그인뷰 컨트롤은 익명 사용자와 인증된 사용자에게 서로 다른 모양을 출력할 때 사용합니다. 로그인하기 전과 로그인한 후의 모습을 다르게 표현할 수 있습니다. 로그인뷰 컨트롤은 AnonymousTemplate, LoggedInTemplate, RoleGroups 세 개의 템플릿을 제공합니다.
17.6.3 LoginName 컨트롤
로그인네임 컨트롤은 인증된 사용자의 이름을 간단히 출력해줍니다.
17.6.4 LoginStatus 컨트롤
로그인상태 컨트롤은 로그인 또는 로그아웃의 링크를 제공하는 컨트롤로, 익명 사용자에게는 로그인을, 인증된 사용자에게는 로그아웃을 보여줍니다.
17.6.5 ChangePassword 컨트롤
암호변경 컨트롤은 인증된 사용자에게 암호 변경 기능을 제공할 때 사용합니다.
17.6.6 PasswordRecovery 컨트롤
암호복구 컨트롤은 사용자가 암호를 모를 때 암호를 찾게 해줍니다. 정확한 데이터를 입력하면 이메일로 암호를 보내주는 역할을 합니다.
17.7 ASP.NET에서 코드 기반으로 인증과 권한 처리하기
ASP.NET에서 기본 제공되는 로그인 컨트롤을 사용하지 않고 인증과 권한 기능을 구현할 때는 다음 네 가지 명령어를 기억하면 됩니다.
- 로그인 처리
System.Web.Security.FormsAuthentication.SetAuthCookie()
System.Web.Security.FormsAuthentication.RedirectFromLoginPage()
- 로그인 확인
User.Identity.IsAuthenticated
- 로그인 이름
User.Identity.Name
- 로그아웃
FormsAuthentication.SignOut()
이 네 가지 명령어를 사용하려면 반드시 Web.config 파일의 인증 모드가 다음과 같이 Forms로 설정되어 있어야 합니다. 자세한 내용은 뒤에서 실습으로 살펴보겠습니다.
<authentication mode="Forms" />
17.7.1 참고: 고전 방식의 세션 인증
회원 관리에서 가장 고전적인 인증 방식은 세션 인증입니다. 세션 인증은 Session 개체를 사용하여 특정 세션 개체에 값이 저장되었는지를 확인하여 인증하는 방식입니다. 간단한 절차는 다음과 같습니다.
17.7.1.1 세션 인증 4가지 코드 조각
- 로그인
Session["UserID"] = "아이디";
- 로그인 확인
if (Session["UserID"].ToString() != "") { // 로그인 상태 }
- 로그인 사용자 이름
<%=Session["UserID"]%>님 반갑습니다.
- 로그아웃
Session.Abandon();
17.8 [실습] 코드 기반 회원 가입, 로그인, 로그인 확인, 로그아웃 구현
17.8.1 소개
이번 실습에서는 ASP.NET을 사용하여 코드 기반으로 로그인, 로그아웃, 로그인 상태 확인, 회원 가입, 암호 변경 등의 기능을 구현해보겠습니다. 회원 관리 관련 핵심 명령어를 학습하기 위해 웹 페이지 디자인은 최소한의 태그로만 진행합니다.
참고
이번 실습 과정을 "ASP.NET 4.6 웹 폼을 사용한 초간단 회원 관리"라는 제목의 동영상 강좌로도 제공하였으니 참고 바랍니다.
17.8.2 따라하기 1: SQL Server 데이터베이스 프로젝트에 인증 관련 테이블 및 저장 프로시저 추가
DotNetNote.Database 프로젝트 생성 (필요 시) DotNetNote.Database 프로젝트가 없으면, SQL Server 데이터베이스 프로젝트에서 새로 만듭니다.
DotNetNote.Database 프로젝트 실행 DotNetNote.Database 프로젝트를 실행합니다.
테이블 생성 SQL Server 데이터베이스 프로젝트에서 테이블을 생성하려면, 다음 그림과 같이 Tables 폴더에 마우스 오른쪽 버튼을 클릭한 후, '추가 > 테이블'을 클릭합니다.
- 새 항목 추가 <새 항목 추가> 창에서 Users.sql이란 이름을 입력하고 추가 버튼을 클릭하여 테이블을 생성합니다.
- Users 테이블 작성 Users.sql 파일의 T-SQL 편집기 영역에 다음 코드를 작성하고 저장합니다. UID는 회원 테이블의 기본 키이고, UserID는 사용자 아이디와 Password는 비밀번호를 담습니다. 나중에 UserName, Email, Address 등을 추가할 수 있는 최소한의 테이블 구조로 만듭니다.
-- [User][0][1] 회원관리를 위한 Users 테이블 생성
-- [0] Users 테이블 생성
Create Table dbo.Users
(
UID Int Identity(1, 1) Primary Key Not Null,
UserID NVarChar(25) Not Null,
[Password] NVarChar(20) Not Null
)
Go
참고 SQL Server에서 다국어를 처리하려면 필드 형식의 VarChar는 모두 NVarChar로 구현해야 합니다. 이 책의 소스에서 모든 VarChar 형식은 NVarChar를 기본으로 합니다.
- 저장 프로시저 생성 이번에는 저장 프로시저를 생성합니다. 다음 그림과 같이 Stored Procedures 폴더에 마우스 오른쪽 버튼 클릭 후 '추가 > 저장 프로시저'를 선택합니다.
- 저장 프로시저 이름 지정 저장 프로시저 이름은 Users_Procedures.sql로 설정하고 추가 버튼을 클릭합니다.
- 저장 프로시저 작성 Users_Procedures.sql 파일의 기본 코드를 모두 제거하고 다음과 같이 작성합니다. 저장 프로시저 여섯 개가 SQL 파일 하나에 위치합니다. 저장 프로시저가 익숙하지 않아도 다음 저장 프로시저는 매우 간단하므로 따라하기 어렵지 않을 것입니다.
-- [User][0][2] Users 관련 저장 프로시저 생성
-- [1] 입력 저장 프로시저
Create Proc dbo.WriteUsers
@UserID NVarChar(25),
@Password NVarChar(20)
As
Insert Into Users Values(@UserID, @Password)
Go
-- [2] 출력 저장 프로시저
Create Proc dbo.ListUsers
As
Select [UID], [UserID], [Password] From Users Order By UID Desc
Go
-- [3] 상세 저장 프로시저
Create Proc dbo.ViewUsers
@UID Int
As
Select [UID], [UserID], [Password] From Users Where UID = @UID
Go
-- [4] 수정 저장 프로시저
Create Proc dbo.ModifyUsers
@UserID NVarChar(25),
@Password NVarChar(20),
@UID Int
As
Begin Tran
Update Users
Set
UserID = @UserID,
[Password] = @Password
Where UID = @UID
Commit Tran
Go
-- [5] 삭제 저장 프로시저
Create Proc dbo.DeleteUsers
@UID Int
As
Delete Users Where UID = @UID
Go
-- [6] 검색 저장 프로시저
Create Proc dbo.SearchUsers
@SearchField NVarChar(25),
@SearchQuery NVarChar(25)
As
Declare @strSql NVarChar(255)
Set @strSql = '
Select * From Users
Where
' + @SearchField + ' Like ''%' + @SearchQuery + '%''
'
Exec(@strSql)
Go
- 로컬 DB에 게시 테이블과 저장 프로시저를 생성하는 SQL 파일을 만들었으면, 이를 로컬DB에 게시합니다. DotNetNote.Database 프로젝트에 마우스 오른쪽 버튼을 클릭하여 게시 메뉴를 선택합니다. 앞장에서 다뤘던 순서대로 로컬DB의 DotNetNote 데이터베이스에 게시해보겠습니다. 다음 그림과 같이 <데이터베이스 게시> 창이 뜨면 <편집> 버튼을 클릭합니다.
- 연결 설정 <연결> 창의 찾아보기 탭에서 로컬DB를 선택하고, 인증은 Windows 인증, 데이터베이스 이름은 DotNetNote로 설정한 후 <확인> 버튼을 클릭합니다.
- 게시 시작 데이터베이스 게시 관련 설정 정보가 기록되었으면 <게시> 버튼을 클릭하여 게시를 진행합니다.
- 게시 완료 확인 게시가 완료되면 데이터 도구 작업 창에 게시가 완료되었다는 메시지가 출력됩니다.
- SQL Server 개체 탐색기 확인 Visual Studio의 <보기 > SQL Server 개체 탐색기>를 열고 로컬DB의 DotNetNote 데이터베이스를 선택하면 다음 그림과 같이 Users 테이블과 저장 프로시저 여섯 개가 추가된 상태를 확인할 수 있습니다.
- SQL Server 데이터베이스 프로젝트 종료 SQL Server 데이터베이스 프로젝트를 통해 테이블과 저장 프로시저 게시가 완료되면 Visual Studio를 종료합니다.
17.8.3 따라하기 2: ASP.NET Web Forms, MVC, Web API가 포함된 웹 프로젝트 생성
- 프로젝트 생성 Visual Studio를 열고 DevUser라는 이름으로 ASP.NET 웹 프로젝트를 생성합니다. Empty 템플릿에 ASP.NET Web Forms, MVC, Web API 관련 참조를 추가하여 생성합니다. 이렇게 세 프로젝트 환경을 통합해서 프로젝트를 생성하는 것을 One ASP.NET이라고 합니다.
이름 | 위치 | ASP.NET 템플릿 선택 | 폴더 및 핵심 참조 추가 |
---|---|---|---|
DevUser | C:\ASP.NET | ASP.NET 4.6 템플릿 - Empty | Web Forms, MVC, Web API |
기본 생성된 프로젝트의 구조는 다음과 같습니다.
- 프로젝트 구성 이번 따라하기 실습을 통해 DevUser 웹 프로젝트에 다음과 같은 폴더 및 파일이 구성됩니다. 각각의 폴더 및 파일에 대한 생성은 하나씩 구성하면서 설명합니다.
- Admin 폴더: 관리자만 접근할 수 있는 페이지
- Documents 폴더: 테이블과 저장 프로시저 구문을 SQL 파일로 저장 (SQL Server 데이터베이스 프로젝트로 대체)
- Models 폴더: 테이블과 일대일로 매핑되는 모델 클래스
- Repositories 폴더: 데이터 입출력을 담당하는 리포지토리 클래스 (일반적으로 Models 폴더에 위치)
- 기타: 각 기능을 구현하는 웹 폼 페이지
Web.config 파일 설정
DevUser 프로젝트의 루트 디렉토리에 있는 Web.config
파일을 열어, 데이터베이스 연결 문자열 정보와 폼 인증 설정을 추가합니다. 인증 방식을 Forms
로 설정해야 합니다. ASP.NET에서 코드 기반 인증을 사용할 때도 반드시 폼 인증 방식을 사용해야 합니다. 데이터베이스 연결 문자열은 다음과 같이 설정합니다. (다른 설정 항목은 생략하였습니다.)
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- [1] 데이터베이스 연결 문자열 -->
<connectionStrings>
<add name="ConnectionString"
connectionString="Data Source=(localdb)\MSSQLLocalDB;
Integrated Security=True;Pooling=False;Database=DotNetNote;"
providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
</appSettings>
<system.web>
<!-- [2] 폼 인증 적용 -->
<authentication mode="Forms">
<forms loginUrl="~/Login.aspx"></forms>
</authentication>
<compilation debug="true" targetFramework="4.6"/>
<httpRuntime targetFramework="4.6"/>
<pages>
</pages>
</system.web>
<system.webServer>
</system.webServer>
<runtime>
</runtime>
<system.codedom>
</system.codedom>
</configuration>
설명
데이터베이스 연결 문자열:
connectionStrings
요소 안에ConnectionString
이라는 이름으로 연결 문자열을 정의합니다.Data Source
는 데이터베이스 서버를 지정하며, 여기서는 로컬 데이터베이스를 사용합니다.Integrated Security=True
는 Windows 인증을 사용하여 데이터베이스에 연결함을 의미합니다.Pooling=False
는 연결 풀링을 사용하지 않도록 설정합니다.Database
는 연결할 데이터베이스 이름을 지정합니다.
폼 인증 설정:
authentication
요소의mode
속성을Forms
로 설정하여 폼 인증을 사용하도록 합니다.forms
요소의loginUrl
속성에 로그인 페이지의 URL을 지정합니다. 여기서는~/Login.aspx
로 설정되어 있습니다.
Default.aspx 페이지 작성 DevUser 프로젝트 루트에 Default.aspx 이름으로 웹 폼 페이지를 생성하고 다음과 같이 작성합니다. LoginView 컨트롤을 사용하여 로그인했을 때와 하지 않았을 때의 뷰 모양을 서로 다르게 표현합니다. 이 부분은 if 문으로 표현해도 무관하나, 이러한 기능을 위해 만들어진 컨트롤을 사용했습니다. Default.aspx.cs 파일은 따로 코드를 작성하지 않습니다.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DevUser.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>회원 관리 - 메인 페이지</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>회원 관리</h1>
<h2>메인 페이지</h2>
<asp:LoginView ID="LoginView1" runat="server">
<AnonymousTemplate>
<!-- 로그인 전 -->
<asp:LoginStatus ID="LoginStatus1" runat="server" LoginText="로그인" /> |
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Register.aspx">회원가입</asp:HyperLink>
</AnonymousTemplate>
<LoggedInTemplate>
<!-- 로그인 후 -->
<asp:LoginStatus ID="LoginStatus2" runat="server" LogoutText="로그아웃" Visible="false" />
<a href="Logout.aspx">로그아웃</a> |
<asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl="~/UserInfo.aspx">
<asp:LoginName ID="LoginName1" runat="server" />
</asp:HyperLink>
</LoggedInTemplate>
</asp:LoginView>
</div>
</form>
</body>
</html>
- 기본 페이지 실행 Default.aspx 페이지를 시작 페이지로 설정 후 웹 브라우저로 실행하면, 다음 그림과 같이 로그인과 회원가입 링크를 제공합니다. 아직 로그인 기능은 구현하지 않았지만, 로그인 후에는 로그아웃과 아이디 링크가 제공될 것입니다.
- UserViewModel 클래스 작성 프로젝트의 Models 폴더에 UserViewModel.cs 이름으로 클래스 파일을 생성하고 다음과 같이 작성합니다. 일반적으로 SQL의 테이블 또는 뷰와 일대일로 매핑되는 클래스는 User, UserModel, UserViewModel 등의 이름으로 테이블 이름과 같게 또는 Model, ViewModel 접미사를 붙입니다.
namespace DevUser.Models
{
public class UserViewModel
{
public int Id { get; set; }
public string UserId { get; set; }
public string Password { get; set; }
}
}
데이터베이스의 Users 테이블은 UID, UserID, Password로 구성했지만, C# 클래스에서는 Id, UserId, Password 형태로 모델 클래스를 구성했습니다. 동일하게 구성하는 것이 좋지만, 이번 실습에서는 이러한 형태도 가능하다는 것을 보여주기 위해 이렇게 작성했습니다.
- UserRepository 클래스 작성 DevUser 프로젝트 루트에 Repositories라는 이름으로 폴더를 생성합니다. Repositories 폴더에 UserRepository.cs 클래스를 만들고 모든 내용을 지운 후 다음과 같이 작성합니다. 회원 관리와 관련하여 더 많은 메서드가 필요하겠지만, 간단히 회원 가입, 회원 정보 상세 보기, 회원 가입 확인 및 회원 정보 수정에서 사용하는 메서드를 구성합니다. ORM을 사용해도 되고 다음과 같이 순수 ADO.NET 코드로 구현해도 됩니다.
using DevUser.Models;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
namespace DevUser.Repositories
{
public class UserRepository
{
// 공통으로 사용될 커넥션 개체
private SqlConnection con;
public UserRepository()
{
con = new SqlConnection();
con.ConnectionString = WebConfigurationManager.ConnectionStrings[
"ConnectionString"].ConnectionString;
}
public void AddUser(string userId, string password)
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "WriteUsers";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@UserID", userId);
cmd.Parameters.AddWithValue("@Password", password);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
public UserViewModel GetUserByUserId(string userId)
{
UserViewModel r = new UserViewModel();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "Select * From Users Where UserID = @UserID";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@UserID", userId);
con.Open();
IDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
r.Id = dr.GetInt32(0);
r.UserId = dr.GetString(1);
r.Password = dr.GetString(2);
}
con.Close();
return r;
}
public void ModifyUser(int uid, string userId, string password)
{
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "ModifyUsers";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@UserID", userId);
cmd.Parameters.AddWithValue("@Password", password);
cmd.Parameters.AddWithValue("@UID", uid);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
public bool IsCorrectUser(string userId, string password)
{
bool result = false;
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "Select * From Users Where UserID = @UserID And Password = @Password";
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("@UserID", userId);
cmd.Parameters.AddWithValue("@Password", password);
SqlDataReader dr = cmd.ExecuteReader();
if (dr.Read())
{
result = true; // 아이디와 암호가 맞는 데이터가 있구나...
}
dr.Close();
con.Close();
return result;
}
}
}
- Register.aspx 페이지 작성 DevUser 프로젝트 루트에 Register.aspx라는 이름으로 웹 폼을 추가합니다. 회원 가입 페이지인 Register.aspx 페이지를 열고 다음과 같이 작성합니다.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Register.aspx.cs" Inherits="DevUser.Register" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>회원 관리 - 회원 가입</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>회원 관리</h1>
<h2>회원 가입</h2>
아이디: <asp:TextBox ID="txtUserID" runat="server"></asp:TextBox><br />
암호: <asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox><br />
<asp:Button ID="btnRegister" runat="server" Text="회원가입" OnClick="btnRegister_Click" /><br />
</div>
</form>
</body>
</html>
- Register.aspx.cs 파일 작성 Register.aspx.cs 파일을 열고 다음과 같이 작성합니다. 코드 후반에 ClientScript의 RegisterClientScriptBlock 메서드를 사용하여 특정 자바스크립트 코드를 바로 실행할 수 있습니다.
using DevUser.Repositories;
using
System;
using System.Web.UI;
namespace DevUser
{
public partial class Register : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnRegister_Click(object sender, EventArgs e)
{
// 데이터 저장
var userRepo = new UserRepository();
userRepo.AddUser(txtUserID.Text, txtPassword.Text);
// 메시지 박스 출력 후 기본 페이지로 이동
string strJs = "<script>alert('가입완료');location.href='Default.aspx';</script>";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "goDefault", strJs);
}
}
}
- 회원 가입 페이지 실행 Register.aspx 페이지를 시작 페이지로 설정 후 웹 브라우저로 실행하면 다음과 같이 페이지가 실행됩니다. 아이디와 암호를 입력해서 회원 가입을 진행해보겠습니다. 예를 들어, 아이디는 “Admin”, 암호는 “123456”으로 연습용 사용자를 만듭니다. 참고로 최소한의 코드로 구성했기 때문에 아이디 확인 및 중복 체크는 제공하지 않습니다.
- Login.aspx 페이지 작성 DevUser 프로젝트 루트에 Login.aspx라는 이름으로 웹 폼을 추가합니다. 로그인 페이지인 Login.aspx 페이지를 열고 다음과 같이 작성합니다.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Login.aspx.cs" Inherits="DevUser.Login" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>회원 관리 - 로그인</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>회원 관리</h1>
<h2>로그인</h2>
아이디: <asp:TextBox ID="txtUserID" runat="server"></asp:TextBox><br />
암호: <asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox><br />
<asp:Button ID="btnLogin" runat="server" Text="로그인" OnClick="btnLogin_Click" />
</div>
</form>
</body>
</html>
- Login.aspx.cs 파일 작성 Login.aspx.cs 파일을 열고 다음과 같이 작성합니다. 리포지토리 클래스에 미리 구현된 IsCorrectUser 메서드를 사용하여 아이디와 암호가 맞는 사용자가 있으면 인증 값을 부여하고, 그렇지 않으면 “잘못된 사용자입니다.” 메시지가 출력됩니다.
using DevUser.Repositories;
using System;
using System.Web.Security;
using System.Web.UI;
namespace DevUser
{
public partial class Login : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnLogin_Click(object sender, EventArgs e)
{
var userRepo = new UserRepository();
if (userRepo.IsCorrectUser(txtUserID.Text, txtPassword.Text))
{
//[!] 인증 부여
if (!String.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
{
// 인증 쿠키값 부여
FormsAuthentication.RedirectFromLoginPage(txtUserID.Text, false);
}
else
{
// 인증 쿠키값 부여
FormsAuthentication.SetAuthCookie(txtUserID.Text, false);
Response.Redirect("~/Welcome.aspx");
}
}
else
{
Page.ClientScript.RegisterStartupScript(
this.GetType(), "showMsg",
"<script>alert('잘못된 사용자입니다.');</script>");
}
}
}
}
- 로그인 페이지 실행 메인 페이지(Default.aspx)를 실행하고, 로그인 링크를 클릭해서 로그인 페이지로 이동하면 ReturnUrl 쿼리 스트링을 포함해서 링크가 실행됩니다.
- 로그인 후 메인 페이지 확인 Login.aspx 페이지에서 정확한 아이디와 암호를 입력한 후 로그인 버튼을 클릭하면 메인 페이지로 이동한 후 다음 그림과 같이 로그아웃과 사용자 아이디에 대한 링크가 제공됩니다.
- Logout.aspx 페이지 작성 DevUser 프로젝트 루트에 Logout.aspx라는 이름으로 웹 폼을 추가합니다. Logout.aspx.cs 파일을 열고 다음과 같이 작성합니다. Logout.aspx 페이지는 따로 UI를 갖지 않는 페이지입니다. 로그인 상태에서 Default.aspx 페이지의 로그아웃 링크를 클릭하면 Logout.aspx 페이지가 실행되고 인증 값이 제거된 후 Default.aspx 다시 이동됩니다.
using System;
namespace DevUser
{
public partial class Logout : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//[!] 로그아웃
System.Web.Security.FormsAuthentication.SignOut();
Response.Redirect("~/Default.aspx");
}
}
}
참고로 LoginStatus 컨트롤을 사용하면 따로 Logout 페이지가 필요 없지만, 링크를 통해서 직접 로그아웃 페이지를 구현하고자 할 때는 이 코드를 사용해야 합니다.
- Welcome.aspx 페이지 작성 DevUser 프로젝트 루트에 Welcome.aspx라는 이름으로 웹 폼을 추가합니다. Welcome.aspx 페이지를 열고 다음과 같이 작성합니다.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Welcome.aspx.cs" Inherits="DevUser.Welcome" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>회원 관리 - 로그인 확인</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>회원 관리</h1>
<h2>로그인 확인</h2>
<asp:Label ID="lblName" runat="server"></asp:Label>님,
반갑습니다.
</div>
</form>
</body>
</html>
- Welcome.aspx.cs 파일 작성 Welcome.aspx.cs 파일을 열고 다음과 같이 작성합니다.
using System;
using System.Web.UI;
namespace DevUser
{
public partial class Welcome : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//[!] 인증 여부 확인: 로그인했으면 참, 그렇지 않으면 거짓을 반환
if (Page.User.Identity.IsAuthenticated)
{
//[!] 인증 이름 출력
lblName.Text = Page.User.Identity.Name;
}
else
{
Response.Redirect("~/Login.aspx"); // 로그인 페이지로 이동
}
}
}
}
- 로그인 후 Welcome 페이지 실행 Login 페이지를 직접 요청해서 들어와서 로그인을 진행하면 따로 ReturnUrl 쿼리 스트링이 제공되지 않습니다. 이런 경우에는 로그인 후에 Welcome.aspx 페이지로 이동하도록 앞서 (12)번에서 구성했습니다. Login.aspx를 실행한 화면에서 로그인하면 Welcome 페이지에 접속합니다.
- UserInfo.aspx 페이지 작성 DevUser 프로젝트 루트에 UserInfo.aspx라는 이름으로 웹 폼을 추가합니다. 회원 정보 상세보기 페이지인 UserInfo.aspx 페이지를 열고 다음과 같이 작성합니다.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="UserInfo.aspx.cs" Inherits="DevUser.UserInfo" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>회원 관리 - 회원 정보 보기</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>회원 관리</h1>
<h2>회원 정보 보기</h2>
UID: <asp:Label ID="lblUID" runat="server"></asp:Label><br />
아이디: <asp:TextBox ID="txtUserID" runat="server"></asp:TextBox><br />
암호: <asp:TextBox ID="txtPassword" runat="server" TextMode="Password"></asp:TextBox><br />
<asp:Button ID="btnModify" runat="server" Text="정보 수정" OnClick="btnModify_Click" />
</div>
</form>
</body>
</html>
- UserInfo.aspx.cs 파일 작성 UserInfo.aspx.cs 파일을 열고 다음과 같이 작성합니다.
using DevUser.Repositories;
using System;
using System.Web.UI;
namespace DevUser
{
public partial class UserInfo : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.User.Identity.IsAuthenticated)
{
Response.Redirect("~/Login.aspx");
}
if (!Page.IsPostBack)
{
DisplayData();
}
}
private void DisplayData()
{
UserRepository userRepo = new UserRepository();
var model = userRepo.GetUserByUserId(Page.User.Identity.Name);
lblUID.Text = model.Id.ToString();
txtUserID.Text = model.UserId;
txtPassword.Text = model.Password;
}
protected void btnModify_Click(object sender, EventArgs e)
{
// 데이터 수정
var userRepo = new UserRepository();
userRepo.ModifyUser(Convert.ToInt32(lblUID.Text), txtUserID.Text, txtPassword.Text);
// 메시지 박스 출력 후 기본 페이지로 이동
string strJs = "<script>alert('수정완료');location.href='Default.aspx';</script>";
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "goDefault", strJs);
}
}
}
- UserInfo 페이지 실행 UserInfo 페이지는 직접 실행할 수 없습니다. 이 페이지는 회원 로그인 후에 해당 사용자로 로그인하면 메인 페이지인 Default.aspx 페이지에서 로그인 사용자 아이디 링크를 클릭하여 접속할 수 있습니다. 처음 로드 시 회원 정보가 바인딩되고 <정보 수정> 버튼을 클릭하면 회원 정보를 수정할 수 있습니다. 실제 웹 사이트를 구현한다면 유효성 검사와 아이디 중복 검사는 필수입니다.
- Admin 폴더 및 Web.config 파일 추가 DevUser 프로젝트 루트에 Admin 폴더를 생성합니다. Admin 폴더에 마우스 오른쪽 버튼을 클릭하여 다음 그림과 같이 웹 구성 파일인 Web.config 파일을 추가합니다.
- Admin 폴더 Web.config 파일 작성 Web.config 파일에 다음과 같이 코드를 작성합니다. Admin 폴더에 Admin과 Red라는 사용자만 접근할 수 있도록 설정했습니다.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<authorization>
<!-- Admin 폴더는 Admin과 Red만 접근 가능 -->
<allow users="Admin, Red"/>
<deny users="*"/>
</authorization>
</system.web>
</configuration>
- Admin 폴더 Default.aspx 페이지 작성 DevUser 프로젝트의 Admin 폴더에 Default.aspx라는 이름으로 웹 폼을 추가합니다. Admin 폴더의 Default.aspx 페이지를 열고 다음과 같이 작성합니다. Default.aspx.cs 파일은 따로 코드를 작성하지 않습니다.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DevUser.Admin.Default" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>관리자 전용 페이지</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>관리자 전용 페이지</h1>
<h2>관리자명: <asp:LoginName ID="LoginName1" runat="server" />
</h2>
</div>
</form>
</body>
</html>
- 관리자 전용 페이지 접속 로그인 페이지에서 Admin 사용자로 로그인합니다. 다음 그림은 Admin 사용자로 로그인한 후에 관리자 전용 페이지인 /Admin/Default.aspx 페이지에 접속한 모습입니다.
17.8.4 마무리
이상으로 코드 기반으로 회원 관리 페이지를 구성해보았습니다. 간단히 아이디와 암호 두 가지 필드만 사용했습니다. 실습을 통해 이름, 주소 등의 정보를 추가하고, 그에 맞게 코드를 구성하는 방법을 익혔을 것입니다.