C# 포트폴리오 도전기(1-3. 로그인 로그 DB에 저장)

min seung moon·2021년 8월 19일
0

C# 포트폴리오

목록 보기
4/10
post-thumbnail
post-custom-banner

1. 로그인 로그

  • 로그를 남기는 방법은 많고 DB가 아닌 .txt파일이나 따로 파일에서 관리하는 경우도 많지만 회사에서 LOGIN LOG를 DB에 남기길래 나도 DB에 남겨보기로 했다
  • 로그에 들어가는 정보
    • 로그인한 회원 번호
    • 로그인한 회원 아이디
    • 로그인 했을 때의 외부 IP
    • 로그인 했을 때 시간
  • 여기에 권한적인 정보도 넣을까 하다가 솔직히 user번호 자체가 고유번호라서 아이디도 필요 없는데 그냥 일단 심심해서 넣었다

01. DB / TABLE

CREATE TABLE Book_User_Log(
	user_no				INT				NULL
	,user_id			NVARCHAR(20)	NULL
	,enter_ip			NVARCHAR(20)	NULL
	,enter_date			DATETIME		NULL
);

02. DB / PROCEDURE / BOOK_LOGIN_I1

  • 첫 INSERT 프로시저이다!
  • 솔직히 검사할것도 없고 그냥 다 찍어넣을거라 할게 없다
  • 외부 IP는 알아두면 어디서 접속했는지 정보도 얻지만 나중에는 특정 IP외에 접속을 막을 수도 있다
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.08.19>
-- Description:	<도서관리프로그램, 로그인 로그>
-- =============================================
CREATE PROCEDURE [dbo].[BOOK_LOGIN_I1]
	@USER_NO	INT
	,@USER_ID	NVARCHAR(20)
	,@ENTER_IP	NVARCHAR(20)
AS
BEGIN
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

	INSERT INTO Book_User_Log VALUES(@USER_NO, @USER_ID, @ENTER_IP, GETDATE());
END
GO

03. Repository / IBookUserRepository.interface

  • InsertLoginLog을 추가해주었다
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);

        bool InsertLoginLog();
    }
}

04. Repository / BookUserRepository.css

  • 이제 크게 어렵지는 않을거라고 생각이 된다
  • 이번에는 외부 아이피를 갖고오기 위해서 GetExternalIPAddress 메서드와 외부 ip를 못 받아올 경우를 대비해 GetInternalIPAddress 메서드로 내부 ip를 반환하는 메서드를 추가했다
    • 외부 아이피는 http://ipinfo.io/ip 홈페이지를 통해서 받아올 수 있고 JSON방식으로도 받아 올 수 있다
    • 실제 외부 아이피를 받아올 때 사용하는 기법이다
using BookManagementProgram.Model;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Net;
using System.Net.Sockets;
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();
            }
        }

        public bool InsertLoginLog()
        {
            try
            {
                string sql = $"EXEC BOOK_LOGIN_I1 @USER_NO = {user.userNo}, @USER_ID = '{user.userId}', @ENTER_IP = '{GetExternalIPAddress()}';";

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

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

        // 외부 IP
        public static string GetExternalIPAddress()
        {
            string externalip = new WebClient().DownloadString("http://ipinfo.io/ip").Trim();

            return externalip ?? GetInternalIPAddress();//null경우 내부 IP 반환;
        }

        // 내부
        // DNS, 단순 도메인 이름 확인 기능이 제공
        // GetGostEntity, 호스트 이름 또는 IP 주소를 IPHostEntry 인스턴스로 확인
        // GetHostName, 로컬 컴퓨터의 호스트 이름을 가져온다
        public static string GetInternalIPAddress()
        {
            var host = Dns.GetHostEntry(Dns.GetHostName());

            foreach (var ip in host.AddressList)
            {
                if (ip.AddressFamily == AddressFamily.InterNetwork)
                {
                    return ip.ToString();
                }
            }

            throw new Exception("인터넷 연결 없음");
        }
    }
}

05. LOGIN / Login.css

  • 간단히 4줄이 추가가 되었다
    • 프로시저에서 번호와 아이디를 받는건 어차피 로그인정보 다 확인했으니 Repository에서 처리하게 해두었고 만약에 Insert가 안된다면 인터넷 문제일 확률이 높기에 DB와 TABLE이 날라가거나 수정이 되지 않는한 그래서 false를 반환하면 경로 문을 띄워준다
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 (!userRepository.InsertLoginLog())
            {
                MessageBox.Show("인터넷을 연결해주세요.");
                return;
            }

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

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

            this.Hide();
        }

        
    }
}

profile
아직까지는 코린이!
post-custom-banner

0개의 댓글