C# 포트폴리오 도전기(1-2. 로그인 창 DB 연결)

min seung moon·2021년 8월 19일
0

C# 포트폴리오

목록 보기
3/10

1. DB 연결

01. USER 관련 테이블

회원정보 테이블
회원번호 PK NOT NULL INT 1000~
회원성명 NAVRCHAR(20) NULL
회원주소 NVARCHAR(50) NULL
회원생년월일 DATETIME

회원 로그인 테이블
회원번호 PK NOT NULL INT 1000~
회원 아이디 NVARCHAR(20) NULL
회원 비밀번호 NVARCHAR(20) NULL
회원가입일 DATETIME NULL
회원탈퇴일 DATETIME NULL
회원권한 INT(1) NULL

회원 권한 테이블
회원권한번호 INT(1) NULL
회원권한명 NVARCHAR(10) NULL

회원 등급 테이블
회원등급번호 INT(1) NULL
회원등급명 NVARCHAR(10) NULL
CREATE TABLE Book_User_Info(
	user_no			INT		NOT NULL	PRIMARY KEY	IDENTITY(1000,1)
	,user_name		NVARCHAR(20)	NULL
	,user_address		NVARCHAR(50)	NULL
	,user_birth		DATETIME	NULL
);

CREATE TABLE Book_User_LogIn(
	user_no			INT			NOT NULL	PRIMARY KEY	IDENTITY(1000,1)
	,user_id		NVARCHAR(20)		NULL
	,user_pw		CHAR(64)		NULL
	,register_date		DATETIME		NULL
	,deregister_date	DATETIME		NULL
	,authority_no		INT			NULL
	,grade_no		INT			NULL
);
-- 0 : admin, 1 : staff, 2 : 손님
CREATE TABLE Book_User_Auth(
	authority_no		INT		NOT NULL	PRIMARY KEY
	,authority_name		NVARCHAR(10)	NULL
);
-- 0 : General Member, 1 : excellent member, 2 : best member
CREATE TABLE Book_User_Grade(
	grade_no		INT		NOT NULL	PRIMARY KEY
	,grade_name		NVARCHAR(5)	NULL
);

INSERT INTO Book_User_Auth VALUES(0, 'admin');
INSERT INTO Book_User_Auth VALUES(1, 'staff');
INSERT INTO Book_User_Auth VALUES(2, '손님'); -- 영어로 변경해주세요! 비공개 되서 한글로 올립니다
SELECT * FROM Book_User_Auth;
INSERT INTO Book_User_Grade VALUES(0, '일반회원');
INSERT INTO Book_User_Grade VALUES(1, '우수회원');
INSERT INTO Book_User_Grade VALUES(2, '최우수회원');
SELECT * FROM Book_User_Grade;

INSERT INTO Book_User_Info(user_name, user_address, user_birth) VALUES('문민승', '대구 남구', '1997.02.05');
SELECT * FROM Book_User_Info;

INSERT INTO Book_User_LogIn(user_id, user_pw, register_date, authority_no, grade_no) VALUES('admin', CONVERT(varbinary(256), '8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918'), GETDATE(), 0, 2); -- admin
SELECT * FROM Book_User_LogIn;

02. DBConn

-1. DBConn / DBConn.cs

  • DB와 연결 후 Connection을 반환해준다
    • 연결 정보는 Properties의 Settings.settings에 저장해두었다
    • App.config에 입력 후 암호화를 해도 좋지만 포트폴리오다보니 일단 가볍게 만들자
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BookManagementProgram.DBConn
{
    class DBConn
    {
        private static string DBIP = Properties.Settings.Default.DBIP;
        private static string DBID = Properties.Settings.Default.DBID;
        private static string DBPW = Properties.Settings.Default.DBPW;
        private static string DB = Properties.Settings.Default.DB;
        private static SqlConnection conn = null;

        public static SqlConnection getConn()
        {
            string connString = "Server=" + DBIP
                                  + ";database=" + DB
                                  + ";uid=" + DBID
                                  + ";pwd=" + DBPW;

            conn = new SqlConnection(connString);

            return conn;
        }
    }
}

03. Model & Repository

-1. Model / User.cs

  • User의 정보를 저장할 객체이다
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BookManagementProgram.Model
{
    class User
    {
        private string user_no;
        private string user_name;
        private string user_address;
        private string user_birth;
        private string user_id;
        private string user_pw;
        private string register_date;
        private string authority_name;
        private string grade_name;

        public string userNo { get { return user_no; } set { user_no = value; } }
        public string userName { get { return user_name; } set { user_name = value; } }
        public string userAddress { get { return user_address; } set { user_address = value; } }
        public string userBirth { get { return user_birth; } set { user_birth = value; } }
        public string userId { get { return user_id; } set { user_id = value; } }
        public string userPw { get { return user_pw; } set { user_pw = value; } }
        public string registerDate { get { return register_date; } set { register_date = value; } }
        public string authorityNo { get { return authority_name; } set { authority_name = value; } }
        public string gradeNo { get { return grade_name; } set { grade_name = value; } }

        public User(string user_no, string user_name, string user_address, string user_birth, string user_id, string user_pw, string register_date, string authority_name, string grade_name)
        {
            this.user_no = user_no;
            this.user_name = user_name;
            this.user_address = user_address;
            this.user_birth = user_birth;
            this.user_id = user_id;
            this.user_pw = user_pw;
            this.register_date = register_date;
            this.authority_name = authority_name;
            this.grade_name = grade_name;
        }

        public User()
        {
        }
    }
}

-2. Repository / IBookUserRepository.interface

  • BookUserRepository 클래스의 추상화한 인터페이스이다
    • 솔직히 User하나만을 위해서는 효율적이지는 않다
    • 그런데 일단 만들어 두고 추후에 필요없으면 삭제 아니면 수정할 수 있어 작성했다
    • 여기서는 로그인과 아이디 찾기, 비밀번호 찾기(?변경) 추상 메서드를 설정했다
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BookManagementProgram.Repository
{
    interface IBookUserRepository
    {
        string Login(string userId, string userPw);

        string FindById(string userNo, string userName);

        bool FindByPassword(string userNo, string userId, string newPassword);
    }
}

-3. Repository / BookUserRepository.cs

  • IBookUserRepository Interface를 상속 받은 후 실제 로직을 작성할 클래스이다
using BookManagementProgram.Model;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace BookManagementProgram.Repository
{
    class BookUserRepository : IBookUserRepository
    {
        public string Login(string userId, string userPw)
        {
            throw new NotImplementedException();
        }
        

        public string FindById(string userNo, string userName)
        {
            throw new NotImplementedException();
        }

        public bool FindByPassword(string userNo, string userId, string newPassword)
        {
            throw new NotImplementedException();
        }

    }
}

04. 로그인

-1. DB / PROCEDURE / BOOK_LOGIN_S1

  • 실무에서 처음으로 얻고 가장 잘 활용하고 있는 기술이 PROCEDURE다
    • 공부를 할 때는 언제 사용하는지 어떻게 사용되는지 몰랐는데 실제로 사용해보니 엄청 편했다
    • C#에서의 로직도 많이 줄어들었고 내가 원하는 만큼 로직을 작성할 수 있어서 편했다
  • UserId와 UserPw를 받아서 해당하는 값이 있는지 확인하고 없으면 에러 메시지를 전달하고 값이 있다면 필요한 정보를 리턴해주었다
USE [BookManagement]
GO
/****** Object:  StoredProcedure [dbo].[BOOK_LOGIN_S1]    Script Date: 2021-08-19 오후 1:18:45 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.08.19,>
-- Description:	<도서관리 프로그램 로그인>
-- =============================================
ALTER PROCEDURE [dbo].[BOOK_LOGIN_S1]
	@USER_ID	NVARCHAR(20)
	,@USER_PW	CHAR(64)
AS
BEGIN
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
	
    IF NOT EXISTS
	(
		SELECT	user_no
		FROM	Book_User_LogIn
		WHERE	user_id	=	@USER_ID
		AND	user_pw	=	@USER_PW
	)
	BEGIN
		RAISERROR('존재하지 않는 사용자 입니다.',16,1)
		RETURN
	END

	SELECT	l.user_no, i.user_name, i.user_address, i.user_birth, l.user_id, l.user_pw, l.register_date, a.authority_name, g.grade_name
	FROM		Book_User_LogIn	as l
	INNER JOIN	Book_User_Info	as i
	ON		l.user_no = i.user_no
	INNER JOIN	Book_User_Auth	as a
	ON		l.authority_no = a.authority_no
	INNER JOIN	Book_User_Grade	as g
	ON		l.grade_no = g.grade_no
	WHERE		user_id	= @USER_ID
	AND		user_pw	= @USER_PW
END

-2. Repository / BookUserRepository.cs

  • 먼저 DBConnection과 로그인 후 데이터를 입력할 변수 그리고 SQL 객체들을 선언해주었다
  • 여기서 가장 중요한건 Login 메서드일것이다
    • 프로시저에서 오류가 날 수 도 있고 그리고 메시지도 오류로 전달해서 try/catch문을 작성해두었다
    • 로그인하기 위한 정보가 DB에 있다면 user 변수에 user의 정보가 저장될 것이다
    • 마지막에는 connection을 닫아주는걸 까먹지 말자
    • transaction을 넣어주는 것도 좋겠지만 그러면 DBConn에서 Connection이 아닌 sqlstring만 반환해주게 수정해서 Repository에서 SQLConnection을 만들어야 해서 건너뛰자!
  • SHA256 암호화 메서드를 작성했다
    • 실제로 비밀번호는 암호화해서 넣어야 되니 여기서 암호화를 하고나서 조회하도록 만들었다
    • 솔직히 고민이 된게 C# 단에서 암호화를 해서 DB로 보낼지 아니면 회사에서 처럼 DB에서 암호화를 해야할지 고민하다가 C#단에서 암호화를 하도록 만들었다 그게 DB로 패스워드를 보낼때 알아보기 힘들것이라고 생각이 돼었기 때문이다
using BookManagementProgram.Model;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace BookManagementProgram.Repository
{
    class BookUserRepository : IBookUserRepository
    {
        private SqlConnection conn = null;
        private SqlCommand cmd = null;
        public static List<User> userList = null;
        public static User user = null;

        public BookUserRepository()
        {
            conn = DBConn.DBConn.getConn();
            cmd = new SqlCommand();
            cmd.Connection = conn;
        }

        public string Login(string userId, string userPw)
        {
            string userNo = string.Empty;

            try
            {
                string sql = $"EXEC BOOK_LOGIN_S1 @USER_ID = '{userId}', @USER_PW = '{Encryption(userPw)}';";

                cmd.CommandText = sql;
                conn.Open();

                // 데이터 출력
                using (SqlDataReader SR = cmd.ExecuteReader())
                {
                    while (SR.Read())
                    {
                        user = new User(
                            SR[0].ToString()
                            , SR[1].ToString()
                            , SR[2].ToString()
                            , SR[3].ToString()
                            , SR[4].ToString()
                            , SR[5].ToString()
                            , SR[6].ToString()
                            , SR[7].ToString()
                            , SR[8].ToString()
                            );
                        userNo = SR[0].ToString();
                    }
                    SR.Close();
                }

                return userNo;
            }
            catch(SqlException e)
            {
                return e.Message;
            }
            finally
            {
                conn.Close();

            }
        }

        // SHA256 암호화 메서드
        public static string Encryption(string data)
        {
            SHA256 sha = new SHA256Managed();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
            StringBuilder stringBuilder = new StringBuilder();
            foreach (byte b in hash)
            {
                stringBuilder.AppendFormat("{0:x2}", b);
            }
            return stringBuilder.ToString();
        }

        public string FindById(string userNo, string userName)
        {
            throw new NotImplementedException();
        }

        public bool FindByPassword(string userNo, string userId, string newPassword)
        {
            throw new NotImplementedException();
        }
    }
}

-3. LOGIN / Login.cs

  • 로그인 버튼 메서드에 6줄 정도 추가가 되었다
    • 줄일려면 줄일 수 있지만 포트폴리오다보니 가독성 좋게 만드는게 좋을것 같아 6줄정도 된다
    • 만약에 입력한 값의 반환값이 숫자가 아니면 오류일 테니 오류 메시지를 보여주게 했다
using BookManagementProgram.Repository;
using System;
using System.Linq;
using System.Windows.Forms;

namespace BookManagementProgram.LOGIN
{
    public partial class Login : Form
    {
        BookUserRepository userRepository = new BookUserRepository();
        public Login()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.CenterScreen;

            if(Properties.Settings.Default.isLoginIdSave)
            {
                id_txt.Text = Properties.Settings.Default.LoginId;
                idSaveCheck_chk.Checked = Properties.Settings.Default.isLoginIdSave;
            }
        }

        // TextBox Focussing
        private void label1_Click(object sender, EventArgs e)
        {
            id_txt.Focus();
        }
        private void label2_Click(object sender, EventArgs e)
        {
            pw_txt.Focus();
        }

        // 비밀번호 보이기 체크박스
        private void showPassword_chk_CheckedChanged(object sender, EventArgs e)
        {
            if (showPassword_chk.Checked)
                pw_txt.PasswordChar = default(char);
            else
                pw_txt.PasswordChar = '*';
        }

        // 아이디 저장 체크박스
        private static void NotSaveID()
        {
            Properties.Settings.Default.isLoginIdSave = false;
            Properties.Settings.Default.Save();
        }
        private void SaveID()
        {
            Properties.Settings.Default.LoginId = id_txt.Text;
            Properties.Settings.Default.isLoginIdSave = true;
            Properties.Settings.Default.Save();
        }

        // 아이디 찾기 라벨
        private void findId_lbl_Click(object sender, EventArgs e)
        {
            (new FindById()).ShowDialog();
        }
        // 비밀번호 찾기 라벨
        private void findPassword_lbl_Click(object sender, EventArgs e)
        {
            (new FindByPassword()).ShowDialog();
        }

        // 로그인 버튼
        private void login_btn_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(id_txt.Text))
            {
                MessageBox.Show("아이디를 입력해주세요.");
                id_txt.Focus();
                return;
            }
            if (string.IsNullOrEmpty(pw_txt.Text))
            {
                MessageBox.Show("비밀번호를 입력해주세요.");
                pw_txt.Focus();
                return;
            }
            
            string result = userRepository.Login(id_txt.Text, pw_txt.Text);
            if (!result.All(char.IsDigit))
            {
                MessageBox.Show(result);
                return;
            }

            if (idSaveCheck_chk.Checked)
            {
                SaveID();
            }
            else
            {
                NotSaveID();
            }

            Main main = new Main();
            main.Show();
            main.BringToFront();

            this.Hide();
        }
    }
}

05. 아이디 찾기

-1. DB / PROCEDURE / BOOK_LOGIN_S2

  • 보면 마지막에 위에는 S1, 여기는 S2이다 이 S는 Select의 S이다
    • Login관련 프로시저는 동일한 이름에 마지막에 결과적으로 이 프로시저의 업무를 작성하고 몇번째인지로 구분한다
    • 이 방법도 회사에서 실제로 사용하고 있는 작성 법이여서 나도 이렇게 작성하고 잇다
  • 입력받은 값과 매치하는 값이 있다면 아이디를 아니면 에러를 반환한다
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.08.19>
-- Description:	<도서관리 프로그램 아이디 찾기>
-- =============================================
CREATE PROCEDURE [dbo].[BOOK_LOGIN_S2]
	@USER_NO	INT
	, @USER_NAME	NVARCHAR(20)
AS
BEGIN
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
	
    IF NOT EXISTS
	(
		SELECT		l.user_id
		FROM		Book_User_Info	as i
		INNER JOIN	Book_User_LogIn	as l
		ON		i.user_no = l.user_no
		WHERE		i.user_no = @USER_NO
		AND		i.user_name = @USER_NAME
	)
	BEGIN
		RAISERROR('존재하지 않는 사용자 입니다.',16,1)
		RETURN
	END

	SELECT		l.user_id
	FROM		Book_User_Info	as i
	INNER JOIN	Book_User_LogIn	as l
	ON		i.user_no = l.user_no
	WHERE		i.user_no = @USER_NO
	AND		i.user_name = @USER_NAME
END
GO

-2. Repository / BookUserRepository.cs

  • 여기서는 꼼수를 썼는데 로그인 할 때는 숫자를 반환해서 로그인이 되었는지 확인했다면 여기서는 반환값이 둘다 문자열이다 그러니 확인할 방법이 없다
    • 그래서 어차피 둘다 메시지 박스로 보여줄 예정이니 아이디일 경우 메시지박스에 보여줄 메시지를 그대로 반환하기로 했다
using BookManagementProgram.Model;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace BookManagementProgram.Repository
{
    class BookUserRepository : IBookUserRepository
    {
        private SqlConnection conn = null;
        private SqlCommand cmd = null;
        public static List<User> userList = null;
        public static User user = null;

        public BookUserRepository()
        {
            conn = DBConn.DBConn.getConn();
            cmd = new SqlCommand();
            cmd.Connection = conn;
        }

        public string Login(string userId, string userPw)
        {
            try
            {
                string sql = $"EXEC BOOK_LOGIN_S1 @USER_ID = '{userId}', @USER_PW = '{Encryption(userPw)}';";

                cmd.CommandText = sql;
                conn.Open();

                // 데이터 출력
                using (SqlDataReader SR = cmd.ExecuteReader())
                {
                    while (SR.Read())
                    {
                        user = new User(
                            SR[0].ToString()
                            , SR[1].ToString()
                            , SR[2].ToString()
                            , SR[3].ToString()
                            , SR[4].ToString()
                            , SR[5].ToString()
                            , SR[6].ToString()
                            , SR[7].ToString()
                            , SR[8].ToString()
                            );
                    }
                    SR.Close();
                }

                return user.userNo;
            }
            catch(SqlException e)
            {
                return e.Message;
            }
            finally
            {
                conn.Close();

            }
        }

        // SHA256 암호화 메서드
        public static string Encryption(string data)
        {
            SHA256 sha = new SHA256Managed();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
            StringBuilder stringBuilder = new StringBuilder();
            foreach (byte b in hash)
            {
                stringBuilder.AppendFormat("{0:x2}", b);
            }
            return stringBuilder.ToString();
        }

        public string FindById(string userNo, string userName)
        {
            try
            {
                string sql = $"EXEC BOOK_LOGIN_S2 @USER_NO = {userNo}, @USER_NAME = '{userName}';";
                string user_id = string.Empty;

                cmd.CommandText = sql;
                conn.Open();

                // 데이터 출력
                using (SqlDataReader SR = cmd.ExecuteReader())
                {
                    while (SR.Read())
                    {
                        user_id = SR[0].ToString();
                    }
                    SR.Close();
                }

                return $"아이디 : {user_id} 입니다.";
            }
            catch (SqlException e)
            {
                return e.Message;
            }
            finally
            {
                conn.Close();

            }
        }

        public bool FindByPassword(string userNo, string userId, string newPassword)
        {
            throw new NotImplementedException();
        }
    }
}

-3. LOGIN / FindById.cs

  • 반환값이 메시지이니 메시지박스만 있으면 된다 1줄이면 오케이
    • 만약 조회한 ID값을 로그인 폼으로 넘기고 싶다면 Reference를 연결해서 전달해주는 방법도 있다
    • 그렇게 되면 반환값을 달리해야하니 빨리 만들고 싶은 현재로서는 일단 완성부터 시키자!
using BookManagementProgram.Repository;
using System;
using System.Windows.Forms;

namespace BookManagementProgram.LOGIN
{
    public partial class FindById : Form
    {
        BookUserRepository userRepository = new BookUserRepository();
        public FindById()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.CenterParent;
        }
        // 취소 버튼
        private void cancel_btn_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // 아이디 찾기 버튼
        private void find_btn_Click(object sender, EventArgs e)
        {
            string memberNo = memberNumber_txt.Text;
            string memberName = memberName_txt.Text;

            if(string.IsNullOrEmpty(memberNo))
            {
                MessageBox.Show("회원 번호를 입력해주세요.");
                memberNumber_txt.Focus();
                return;
            }
            if(string.IsNullOrEmpty(memberName))
            {
                MessageBox.Show("회원 성명를 입력해주세요.");
                memberName_txt.Focus();
                return;
            }

            MessageBox.Show(userRepository.FindById(memberNo, memberName));
        }

        private void label1_Click(object sender, EventArgs e)
        {
            memberNumber_txt.Focus();
        }

        private void label2_Click(object sender, EventArgs e)
        {
            memberName_txt.Focus();
        }
    }
}

05. 비밀번호 찾기(?변경)

-1. DB / PROCEDURE / BOOK_LOGIN_U1

  • 첫 Select가 아닌 프로시저인데요!
  • 그런데 왜 IF에서 Select를 사용하나 싶은분도 계실텐데요!
    • 아시다 시피 IF 구절 안에서 UPDATE해도 반환값이 조건의 결과가 되지 프로시저의 반환값이 되지는 않기에 먼저 입력한 값과 일치하는 회원이 있는지 확인하고 있다면 UPDATE하고 아니면 에러 메시지를 전달합니다!
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.08.19>
-- Description:	<도서관리 프로그램 비밀번호 조회>
-- =============================================
CREATE PROCEDURE [dbo].[BOOK_LOGIN_U1]
	@USER_NO	INT
	,@USER_ID	NVARCHAR(20)
	,@NEW_PW	CHAR(64)
AS
BEGIN
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
	
    IF NOT EXISTS
	(
		SELECT		user_no
		FROM		Book_User_LogIn
		WHERE		user_no = @USER_NO
		AND			user_id	= @USER_ID
	)
	BEGIN
		RAISERROR('존재하지 않는 사용자 입니다.',16,1)
		RETURN
	END

	UPDATE	Book_User_LogIn 
	SET		user_pw = @NEW_PW
	WHERE	user_no = @USER_NO
	AND		user_id = @USER_ID;
END
GO

-2. Repository / BookUserRepository.cs

  • 비밀번호 변경은 성공했는지 실패했는지만 알려드리면 되기때문에 성공하면 true 아니면 false를 반환 합니다
    • 이번에는 ExecuteReader 메서드가 아닌 ExecuteNonQuery인데요!
    • ExecuteReader는 Select하여 결과값을 받아올 때 사용되구요!
    • ExecuteNonQuery는 Insert, Update, Delete 등 데이터의 반환이 아닌 Query의 성공여부를 판단할 때는 ExecuteNonQuery를 사용하고 ExecuteNonQuery 메서드는 Query가 영향을 준 행의 수가 반환되기에 0보다 크면 1개라도 영향을 주었다는 거겠죠!
using BookManagementProgram.Model;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Text;

namespace BookManagementProgram.Repository
{
    class BookUserRepository : IBookUserRepository
    {
        private SqlConnection conn = null;
        private SqlCommand cmd = null;
        public static List<User> userList = null;
        public static User user = null;

        public BookUserRepository()
        {
            conn = DBConn.DBConn.getConn();
            cmd = new SqlCommand();
            cmd.Connection = conn;
        }

        // 로그인 로직
        public string Login(string userId, string userPw)
        {
            try
            {
                string sql = $"EXEC BOOK_LOGIN_S1 @USER_ID = '{userId}', @USER_PW = '{Encryption(userPw)}';";

                cmd.CommandText = sql;
                conn.Open();

                // 데이터 출력
                using (SqlDataReader SR = cmd.ExecuteReader())
                {
                    while (SR.Read())
                    {
                        user = new User(
                            SR[0].ToString()
                            , SR[1].ToString()
                            , SR[2].ToString()
                            , SR[3].ToString()
                            , SR[4].ToString()
                            , SR[5].ToString()
                            , SR[6].ToString()
                            , SR[7].ToString()
                            , SR[8].ToString()
                            );
                    }
                    SR.Close();
                }

                return user.userNo;
            }
            catch(SqlException e)
            {
                return e.Message;
            }
            finally
            {
                conn.Close();
            }
        }

        // SHA256 암호화 메서드
        public static string Encryption(string data)
        {
            SHA256 sha = new SHA256Managed();
            byte[] hash = sha.ComputeHash(Encoding.ASCII.GetBytes(data));
            StringBuilder stringBuilder = new StringBuilder();
            foreach (byte b in hash)
            {
                stringBuilder.AppendFormat("{0:x2}", b);
            }
            return stringBuilder.ToString();
        }

        // 아이디 찾기 로직
        public string FindById(string userNo, string userName)
        {
            try
            {
                string sql = $"EXEC BOOK_LOGIN_S2 @USER_NO = {userNo}, @USER_NAME = '{userName}';";
                string user_id = string.Empty;

                cmd.CommandText = sql;
                conn.Open();

                // 데이터 출력
                using (SqlDataReader SR = cmd.ExecuteReader())
                {
                    while (SR.Read())
                    {
                        user_id = SR[0].ToString();
                    }
                    SR.Close();
                }

                return $"아이디 : {user_id} 입니다.";
            }
            catch (SqlException e)
            {
                return e.Message;
            }
            finally
            {
                conn.Close();
            }
        }

        // 비밀번호 찾기 로직
        public bool FindByPassword(string userNo, string userId, string newPassword)
        {
            try
            {
                string sql = $"EXEC BOOK_LOGIN_U1 @USER_NO = {userNo}, @USER_ID = '{userId}', @NEW_PW = '{Encryption(newPassword)}';";

                cmd.CommandText = sql;
                conn.Open();

                return cmd.ExecuteNonQuery() > 0 ? true : false;
            }
            catch (SqlException e)
            {
                return false;
            }
            finally
            {
                conn.Close();
            }
        }
    }
}

-3. LOGIN / FindByPassword.cs

  • 변경되었다면 변경되었다는 메시지와 함께 창을 닫아주구요! 만약 실패했다면 어디가 실패한지 확인할 수 있게 창을 그대로 두었습니다!
using BookManagementProgram.Repository;
using System;
using System.Data;
using System.Linq;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BookManagementProgram.LOGIN
{
    public partial class FindByPassword : Form
    {
        private int _duration = 0;
        private string _auth_code = "";
        BookUserRepository userRepository = new BookUserRepository();

        public FindByPassword()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.CenterParent;
        }
        // 인증번호 요청 버튼
        private void authenticationRequest_btn_Click(object sender, EventArgs e)
        {
            if(CheckTextBox())
            {
                string email = memberEmail_txt.Text;
                if(CheckEmailPattern(email))
                {
                    GmailRun(email);
                }
            }
        }

        // 인증번호 확인 버튼
        private void checkAuthentication_btn_Click(object sender, EventArgs e)
        {
            if (authenticationNumber_txt.Text.Trim().Equals(_auth_code))
            {
                MessageBox.Show("인증 되었습니다");
                ResetTimerAndCode();
                newPassword_txt.ReadOnly = false;
                newPassword_txt.Focus();
            }
            else
            {
                MessageBox.Show("다시 확인해주세요");
            }
        }

        // 비밀번호 변경 버튼
        private void changePassword_btn_Click(object sender, EventArgs e)
        {
            if(CheckTextBox())
            {
                if(newPassword_txt.Text.Length > 0)
                {
                    if(userRepository.FindByPassword(memberNumber_txt.Text, memberID_txt.Text, newPassword_txt.Text))
                    {
                        MessageBox.Show("비밀번호 변경 되었습니다");
                        this.Close();
                        return;
                    }
                    MessageBox.Show("비밀번호 변경에 실패하였습니다.");
                }
            }
        }

        // 취소
        private void cancel_btn_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private bool CheckTextBox()
        {
            if(string.IsNullOrEmpty(memberNumber_txt.Text))
            {
                MessageBox.Show("회원의 성함을 입력해주세요.");
                memberNumber_txt.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(memberID_txt.Text))
            {
                MessageBox.Show("회원의 아이디를 입력해주세요.");
                memberID_txt.Focus();
                return false;
            }
            if (string.IsNullOrEmpty(memberEmail_txt.Text))
            {
                MessageBox.Show("회원의 이메일을 입력해주세요.");
                memberEmail_txt.Focus();
                return false;
            }
            return true;
        }

        private bool CheckEmailPattern(string email)
        {
            string pattern = @"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?";
            if(Regex.IsMatch(email, pattern))
            {
                return true;
            }
            else
            {
                MessageBox.Show("이메일을 확인해주세요.");
                memberEmail_txt.Focus();
                return false;
            }
        }

        // 랜덤 코드 생성
        private string getRandomCode()
        {
            Random rand = new Random();
            string input = "abcdefghijklmnopqrstuvxyz0123456789";

            var chars = Enumerable.Range(0, 6).Select(x => input[rand.Next(0, input.Length)]);

            return new string(chars.ToArray());
        }

        // 타이머 카운트 다운
        private void CountDown(object sender, EventArgs e)
        {
            if (_duration == 0 || _duration < 0)
            {
                ResetTimerAndCode();
                MessageBox.Show("인증 시간이 초과되었습니다.");
                return;
            }
            _duration--;
            timer_lbl.Text = _duration.ToString();
        }

        // 타이머 및 코드 초기화
        private void ResetTimerAndCode()
        {
            timer1.Stop();
            timer1.Dispose();
            _auth_code = "";
        }

        // gmail
        private async void GmailRun(string email)
        {
            // 타이머 초기화 및 인증번호 생성
            _duration = 60;
            _auth_code = getRandomCode();
            timer1.Stop();
            timer1 = new Timer();
            timer1.Tick += new EventHandler(CountDown);
            timer1.Interval = 1000;
            timer1.Start();

            await Task.Run(() => sendGmailAsync(email));
            //auth_btn.Enabled = true;
        }
        private void sendGmailAsync(string email)
        {
            MailMessage mailMessage = new MailMessage();

            mailMessage.From = new MailAddress(Properties.Settings.Default.GmailID);
            mailMessage.To.Add(email);
            mailMessage.Subject = "인증코드";
            mailMessage.Body = $"인증 코드 : {_auth_code}";
            SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");
            SmtpServer.Port = 587;
            SmtpServer.EnableSsl = true;
            SmtpServer.UseDefaultCredentials = false;
            SmtpServer.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
            SmtpServer.Credentials = new System.Net.NetworkCredential(Properties.Settings.Default.GmailID, Properties.Settings.Default.GmailPW);

            SmtpServer.Send(mailMessage);
        }

        private void label1_Click(object sender, EventArgs e)
        {
            memberNumber_txt.Focus();
        }
        private void label2_Click(object sender, EventArgs e)
        {
            memberID_txt.Focus();
        }

        private void label3_Click(object sender, EventArgs e)
        {
            memberEmail_txt.Focus();
        }

        private void label4_Click(object sender, EventArgs e)
        {
            authenticationNumber_txt.Focus();
        }

        private void label5_Click(object sender, EventArgs e)
        {
            newPassword_txt.Focus();
        }
    }
}

profile
아직까지는 코린이!

0개의 댓글