C# 알아가기 (2. 로그인 폼 만들어보기 - 아이디 찾기, 비밀번호 찾기)

min seung moon·2021년 8월 3일
0

C#알아가기

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

0. 결과

01. 내가 만든 결과



02. 벤치마킹

https://github.com/xv/xrails-login-ui

  • 이번에는 구글에서 찾다가 한 디자인을 밴치마킹을 했다 하지만 코드는 전부 제가 하나 하나 기능 찾아가면서 작성을 했습니다

03. 기능

  • 로그인, 아이디 저장, 비밀번호 확인, 아이디 찾기, 비밀번호 찾기

04. API

  • Gmail Send Email
  • Twilo(추가)
  • SendGrid(추가)
  • QR 인증(추가)

1. API 회원가입

01. Google(Gmail)

  • 기존 Google 계정보다는 하나 새롭게 사용하시는걸 추천드려요!
    • 왜냐하면 Gmail을 사용해서 이메일 보낼 때 계정 보안이 취약해지기 때문이죠!

02. Twilo(SMS)

https://www.twilio.com/

  • 회원 가입 해주시구요!
    • 번호를 하나 받아서 사용하시면 되구요 받은 번호로 SMS가 전송된다고 보시면 되요!

03. SendGrid(Email)

https://sendgrid.com/

  • 회원 가입 해주시구요!

  • 발신자 인증을 꼭 해주셔야 돼요!

    • 그래야 발신자를 통해서 메일이 날라가요
    • 발신자는 선택해서 인증해주세요~!

  • API Key를 생성할 때 SG.으로 시작하는 비밀번호 받는데 그게 가장 중요합니다!

2. DB

01. DB 설계

  • DataBase : MS SQL
  • DB Name : Test
  • Table Name : TestLogin
    • ID Column은 idx와 같은 고유 번호이다, IDENTITY로 자동 증가 설정

02. PROCEDURE

  • LOGIN_S1
    • 로그인 체킹
GO
/****** Object:  StoredProcedure [dbo].[SP_LOGIN_S2]    Script Date: 2021-08-03 오후 1:59:23 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.07.26>
-- Description:	<로그인 체킹에 회사코드 추가>
-- =============================================
ALTER PROCEDURE [dbo].[LOGIN_S1]
	@COM_CODE	NVARCHAR(20)
	,@EMP_CODE	NVARCHAR(20)
	,@EMP_PW	VARCHAR(40)
AS
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

	IF NOT EXISTS
	(
		SELECT	ID
		FROM	TEST_B_LOG2
		WHERE	COM_CODE	=	@COM_CODE
		AND		EMP_CODE	=	@EMP_CODE
		AND		EMP_PW		=	HASHBYTES('SHA2_256', @EMP_PW)
	)
	BEGIN
		RAISERROR('존재하지 않는 사용자 입니다.',16,1)
		RETURN
	END

	SELECT	*
	FROM	TEST_B_LOG2
	WHERE	COM_CODE	=	@COM_CODE
	AND		EMP_CODE	=	@EMP_CODE
	AND		EMP_PW		=	HASHBYTES('SHA2_256', @EMP_PW)
  • LOGIN_S2
    • 아이디 찾기
GO
/****** Object:  StoredProcedure [dbo].[SP_LOGIN_S3]    Script Date: 2021-08-03 오후 1:59:48 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.07.27>
-- Description:	<아이디 찾기>
-- =============================================
ALTER PROCEDURE [dbo].[LOGIN_S2]
	@ID			INT
	,@COM_CODE	NVARCHAR(20)
AS
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

	IF NOT EXISTS
	(
		SELECT	EMP_CODE
		FROM	TEST_B_LOG2
		WHERE	ID			=	@ID
		AND		COM_CODE	=	@COM_CODE
	)
	BEGIN
		RAISERROR('존재하지 않는 사용자 입니다.',16,1)
		RETURN
	END

	SELECT	EMP_CODE
	FROM	TEST_B_LOG2
	WHERE	ID			=	@ID
	AND		COM_CODE	=	@COM_CODE
  • LOGIN_U1
    • 비밀번호 변경
    • 비밀번호는 암호화해서 수정(SHA2_256)
GO
/****** Object:  StoredProcedure [dbo].[SP_LOGIN_U1]    Script Date: 2021-08-03 오후 2:00:21 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:		<문민승>
-- Create date: <2021.07.27>
-- Description:	<비밀번호 변경>
-- =============================================
ALTER PROCEDURE [dbo].[LOGIN_U1]
	@EMP_ID		NVARCHAR(20)
	,@EMP_PW	VARCHAR(40)
AS
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

	UPDATE	TEST_B_LOG2
	SET		EMP_PW		=	HASHBYTES('SHA2_256', @EMP_PW)
	WHERE	EMP_CODE	=	@EMP_ID
	
	IF
	(
		@@ERROR != 0 OR @@ROWCOUNT < 1
	)
	BEGIN
		RAISERROR('존재하지 않는 사용자 입니다.',16,1)
		RETURN
	END

2. 코드

01. Custom Controlls

-1. CustomPlaceholderBorderBottomTextBox.cs

  • Placeholder기능과 border 기능을 추가한 textbox
using DH.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class CustomPlaceholderBorderBottomTextBox : TextBox
    {
        private string _placeholder = "데이터를 입력해주세요.";
        private Color _placeholderColor = Color.DarkGray;
        private Color _writeColor = Color.Black;
        private Color _bottomBorderColor = Color.White;
        private Color _onFocusColor = Color.Red;

        public CustomPlaceholderBorderBottomTextBox()
        {
            InitializeComponent();

            // border 삭제
            BorderStyle = BorderStyle.None;
            AutoSize = false;

            // textbox에 label(border bottom 역할) 넣기
            Controls.Add(new Label
            {
                Height = 2,
                Dock = DockStyle.Bottom,
                BackColor = _bottomBorderColor

            });

            //처음 공백 Placeholder 지정
            this.ForeColor = _placeholderColor;
            this.Text = _placeholder;
            //텍스트박스 커서 Focus 여부에 따라 이벤트 지정
            this.GotFocus += RemovePlaceholder;
            this.LostFocus += SetPlaceholder;

        }

        // 플레이스 홀더 삭제
        private void RemovePlaceholder(object sender, EventArgs e)
        {
            TextBox txt = (TextBox)sender;
            if (txt.Text == _placeholder)
            { //텍스트박스 내용이 사용자가 입력한 값이 아닌 Placeholder일 경우에만, 커서 포커스일때 빈칸으로 만들기
                txt.ForeColor = _writeColor; //사용자 입력 진한 글씨
                txt.Text = string.Empty;
                if (txt.Name.IndexOf("pw", StringComparison.OrdinalIgnoreCase) >= 0 || txt.Name.IndexOf("password", StringComparison.OrdinalIgnoreCase) > 0) this.PasswordChar = '*';
            }
        }

        // 플레이스 홀더 적용
        private void SetPlaceholder(object sender, EventArgs e)
        {
            TextBox txt = (TextBox)sender;
            if (string.IsNullOrWhiteSpace(txt.Text))
            {
                //사용자 입력값이 하나도 없는 경우에 포커스 잃으면 Placeholder 적용해주기
                txt.ForeColor = _placeholderColor; //Placeholder 흐린 글씨
                txt.Text = _placeholder;
                if (txt.Name.IndexOf("pw", StringComparison.OrdinalIgnoreCase) >= 0 || txt.Name.IndexOf("password", StringComparison.OrdinalIgnoreCase) > 0) { this.PasswordChar = default(char); }
            }
        }

        public string Placeholder
        {
            get { return _placeholder; }
            set
            {
                _placeholder = value;
                this.Text = value;
            }
        }

        public Color PlaceholderColor
        {
            get { return _placeholderColor; }
            set { _placeholderColor = value; }
        }

        public Color WriteColor
        {
            get { return _writeColor; }
            set { _writeColor = value; }
        }

        // Hides the BorderStyle from Control Property,
        // so to avoid people changing BorderStyle of the TextBox
        [Browsable(false)]
        public new BorderStyle BorderStyle
        {
            get { return base.BorderStyle; }
            set { base.BorderStyle = value; }
        }

        public Color BottomBorderColor
        {
            get { return _bottomBorderColor; }
            set
            {
                _bottomBorderColor = value;
                Controls[0].BackColor = _bottomBorderColor;
            }
        }

        public Color BottomBorderOnFocusColor
        {
            get { return _onFocusColor; }
            set { _onFocusColor = value; }
        }

        private void CustomBorderTextBox_Enter(object sender, EventArgs e)
        {
            Controls[0].BackColor = _onFocusColor;
        }

        private void CustomBorderTextBox_Leave(object sender, EventArgs e)
        {
            Controls[0].BackColor = _bottomBorderColor;
        }

        private void CustomPlaceholderBorderBottomTextBox_TextChanged(object sender, EventArgs e)
        {
            if (this.Text.Length > this.MaxLength - 1) DH.Data.Excute.Msg(Excute.Message_Type.ETC, $"{this.MaxLength}까지 작성 가능합니다.");
        }
    }
}

-2. CustomRoundButton.cs

  • 둥근 모서리 버튼
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class CustomRoundButton : Button
    {
        private int _cornerRadius = 40;

        public CustomRoundButton()
        {
            InitializeComponent();
            RoundBorderForm(this);
        }

        private void RoundBorderForm(Button button)
        {
            Rectangle Bounds = new Rectangle(0, 0, button.Width, button.Height);

            float r2 = _cornerRadius / 2f;
            GraphicsPath graphicsPath = new GraphicsPath();
            graphicsPath.AddArc(Bounds.X, Bounds.Y, 1, 1, 180, 90);
            graphicsPath.AddLine(Bounds.X + r2, Bounds.Y, Bounds.Width - r2, Bounds.Y);
            graphicsPath.AddArc(Bounds.X + Bounds.Width - _cornerRadius, Bounds.Y, _cornerRadius, _cornerRadius, 270, 90);
            graphicsPath.AddLine(Bounds.Width, Bounds.Y + r2, Bounds.Width, Bounds.Height - r2);
            graphicsPath.AddArc(Bounds.X + Bounds.Width - _cornerRadius,
                             Bounds.Y + Bounds.Height - _cornerRadius, _cornerRadius, _cornerRadius, 0, 90);
            graphicsPath.AddLine(Bounds.Width - r2, Bounds.Height, Bounds.X + r2, Bounds.Height);
            //graphicsPath.AddArc(Bounds.X, Bounds.Y + Bounds.Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
            graphicsPath.AddArc(Bounds.X, Bounds.Y + Bounds.Height, 1, 1, 90, 90);
            graphicsPath.AddLine(Bounds.X, Bounds.Height - r2, Bounds.X, Bounds.Y + r2);
            graphicsPath.CloseFigure();

            button.Region = new Region(graphicsPath);
            button.Show();
        }

        public int CornerRadius
        {
            get { return _cornerRadius; }
            set { _cornerRadius = value; }
        }

        private void CustomRoundButton_Resize(object sender, EventArgs e)
        {
            RoundBorderForm(this);
        }
    }
}

02. POPUP

-1. FindByIdPopUp.cs

using DH.Connect;
using DH.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class FindByIdPopUp : FrmInherit
    {
        public FindByIdPopUp()
        {
            InitializeComponent();
        }

        private void find_by_id_btn_ButtonClick(object sender, EventArgs e)
        {
            string comCode = com_code_txt.Value;
            string id = id_txt.Value;
            if (comCode.Trim() == "")
            {
                // "회사 코드를 입력해주세요." 메시지 박스 출력
                com_code_txt.Focus();
                return;
            }
            if (id.Trim() == "")
            {
                // "사원 번호를 입력해주세요." 메시지 박스 출력
                id_txt.Focus();
                return;
            }

            // 아이디 찾기 프로시저 수행

            if (// 프로시저 결과)
            {
                // $"아이디는 {excute.dt.Rows[0]["EMP_CODE"].ToString()} 입니다." 메시지 박스 출력
            }
            else
            {
                // Error 메시지 박스 출력
            }
        }

        private void close_btn_ButtonClick(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}

-2. FindByPasswordPopUp.cs

  • UI 작동 안하는 부분을 해결하기 위해 await 사용
  • email 아이디와 비밀번호는 개인정보라서 저는 테스트로 Properties.Settings.Setting에 입력을 해두었습니다.
    • Properties.Settings.Default.GmailID 처럼 사용
  • 나중에 App.config로 옮길 예정
using DH.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class FindByPasswordPopUp : FrmInherit
    {
        private readonly string _email = Properties.Settings.Default.GmailID; // from
        private readonly string _pw = Properties.Settings.Default.GmailPW;  // password
        private int _duration = 0;  // 인증 타이머
        private string _auth_code = "";  // 인증 번호

        public FindByPasswordPopUp()
        {
            InitializeComponent();
        }

        // 닫기 버튼
        private void close_btn_ButtonClick(object sender, EventArgs e)
        {
            this.Close();
        }

        // 인증번호 발송 버튼
        private void send_email_btn_ButtonClick(object sender, EventArgs e)
        {
            Run();
        }

        // 이메일 발송 비동기 처리
        private async void Run()
        {
            string email = email_txt.Text;

            if (EmailValdate(email))
            {

                // 타이머 초기화 및 인증번호 생성
                _duration = 60;
                _auth_code = GetRandomCode();
                timer1 = new Timer();
                timer1.Tick += new EventHandler(CountDown);
                timer1.Interval = 1000;
                timer1.Start();

                await Task.Run(() => SendEmailFromGmail(email));
            }
            else
            {
                Excute.Msg(Excute.Message_Type.ETC, "이메일을 제대로 확인해주세요.");
            }
        }
        // 이메일 발송 비동기 함수
        private void SendEmailFromGmail(string email)
        {
            MailMessage mailMessage = new MailMessage();

            // mailMessage.From = new MailAddress("전송하는 계정 주소", "표시 이름", System.Text.Encoding.UTF8);
            mailMessage.From = new MailAddress(_email, "인증번호", Encoding.UTF8);
            mailMessage.To.Add(email);
            mailMessage.Subject = "인증코드";
            mailMessage.SubjectEncoding = Encoding.UTF8;
            mailMessage.Body = $"인증 코드 : {_auth_code}";
            // 본문의 포맷에 따라 선택
            mailMessage.IsBodyHtml = false;
            mailMessage.BodyEncoding = Encoding.UTF8;
            SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");
            SmtpServer.Port = 587;
            // SSL 사용 여부
            SmtpServer.EnableSsl = true;
            SmtpServer.UseDefaultCredentials = false;
            SmtpServer.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
            // 보낼 이메일 아이디랑 비밀번호 입력
            SmtpServer.Credentials = new System.Net.NetworkCredential(_email, _pw);

            SmtpServer.Send(mailMessage);
        }

        // 인증번호 확인 버튼
        private void check_auth_btn_ButtonClick(object sender, EventArgs e)
        {
            if (auth_code_txt.Text.Trim().Equals(_auth_code))
            {
                // 인증 되었습니다 메시지 박스 출력
                ResetTimerAndCode();
                new_password_txt.ReadOnly = false;
                new_password_txt.Focus();
            }
            else
            {
                // 다시 확인해주세요 메시지 박스 출력
            }
        }

        // 비밀번호 변경 버튼
        private void change_password_btn_ButtonClick(object sender, EventArgs e)
        {
            string empId = emp_id_txt.Text;
            string newPassword = new_password_txt.Text;

            if (empId.Trim() == "")
            {
                // 아이디를 입력해주세요 메시지 박스 출력
                emp_id_txt.Focus();
                return;
            }
            if (newPassword.Trim() == "")
            {
                // 비밀번호를 입력해주세요 메시지 박스 출력
                new_password_txt.Focus();
                return;
            }

            // 비밀번호 변경 프로시저 수행 코드

            if (excute.returnResult)
            {
                // 비밀번호 변경 성공 코드 작성 필
                this.Close();
            }
            else
            {
                Excute.Msg(Excute.Message_Type.Sql_Error);
            }
        }

        // 이메일 인증
        public bool EmailValdate(string email)
        {
            return Regex.IsMatch(email, @"[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])?");
        }

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

        // 랜덤 코드 생성
        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 ResetTimerAndCode()
        {
            timer1.Stop();
            timer1.Dispose();
            _auth_code = "";
        }
    }
}

03. 메인 폼

using DH.Connect;
using DH.Data;
using DH_WMS._0000_공통.Custom_Component;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Net;
using System.Windows.Forms;

namespace DH_WMS
{
	public partial class FrmLogin : FrmInherit
	{

		public FrmLogin()
		{
			InitializeComponent();
		}

		private void simpleButton1_Click(object sender, EventArgs e)
		{
			// 아이디 저장 이벤트
			if (emp_id_save_chk.Checked) SaveID();
			else NotSaveID();

			// string comCode = com_code_txt.Text;
			string comCode = com_code_txt.Text; // 추가
			string empId = emp_id_txt.Text;
			string empPw = emp_pw_txt.Text;
		
        		// 프로시저 수행 코드
                	/* ...*/

			if (로그인 성공했는지 확인)
			{
            			//  메인 폼 실행
				Form main = new Form();
				main.Show();
				main.BringToFront();
				this.Hide();
			}
			else
            		{
                		// 로그인 실패 메시지 박스 출력
            		}
            		*/
        }
        

        // 체크박스 비밀번호 캐릭터 설정 이벤트
        private void emp_pw_chk_CheckedChanged(object sender, EventArgs e)
		{
			if (emp_pw_visible_chk.Checked)
				emp_pw_txt.PasswordChar = default(char);
			else
				emp_pw_txt.PasswordChar = '*';
		}

		// form load 이벤트(아이디 저장 이벤트)
		private void FrmLogin_Load(object sender, EventArgs e)
		{
			// LoginIdSetting이 true이면 emp_id_txt에 저장된 아이디 보이기
			if (Properties.Settings.Default.LoginIdSetting)
			{
				com_code_txt.Text = Properties.Settings.Default.ComCodeSave; // 추가
				emp_id_txt.Text = Properties.Settings.Default.LoginIdSave;
				emp_id_save_chk.Checked = true;
			}
		}

		private static void NotSaveID()
		{
			Properties.Settings.Default.LoginIdSetting = false;
			Properties.Settings.Default.Save();
		}

		private void SaveID()
		{
			Properties.Settings.Default.ComCodeSave = com_code_txt.Text; // 추가
			Properties.Settings.Default.LoginIdSave = emp_id_txt.Text;
			Properties.Settings.Default.LoginIdSetting = true;
			Properties.Settings.Default.Save();
		}

		// 외부 IP 갖고오기
		public static string GetExternalIPAddress()
		{
			string externalip = new WebClient().DownloadString("http://ipinfo.io./ip").Trim();
			
			if (String.IsNullOrWhiteSpace(externalip))
			{
				externalip = GetInternalIPAddress();
			}

			return externalip;
		}
		// 내부 ip(0(IPv6), 1(IPv4))
		public static string GetInternalIPAddress(int i = 1)
		{
			String strHostName = string.Empty;
			IPHostEntry ipEntry = Dns.GetHostEntry(Dns.GetHostName());
			IPAddress[] addr = ipEntry.AddressList;

			return addr[i].ToString();
		}
        
	// 아이디 찾기 팝업
        private void find_by_id_lbl_Click(object sender, EventArgs e)
        {
			FindByIdPopUp form = new FindByIdPopUp();
			form.ShowDialog();
		}

	// 비밀번호 찾기 팝업
        private void find_by_password_lbl_Click(object sender, EventArgs e)
        {
			FindByPasswordPopUp form = new FindByPasswordPopUp();
			form.ShowDialog();
        }
    }
}

03. 비밀번호 찾기 다양한 인증 테스트

  • 테스트는 다른 프로젝트에 코드 작성해서 사용하기에 디자인은 달라요~!
  • 나에게 맞는 기능을 사용하세요~!

-1. Email, SMS 비밀번호 찾기

  • Twilio, SendGrid nuget에서 설치
using SendGrid;
using SendGrid.Helpers.Mail;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using System.Configuration;

namespace popup
{
    public partial class FindByPWMS : Form
    {
        private int _duration = 0;
        private string _auth_code = "";

        public FindByPWMS()
        {
            InitializeComponent();
        }

        // 창 닫기 이벤트
        private void cancle_btn_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // sendgrid
        private void send_grid_btn_Click(object sender, EventArgs e)
        {
            SendGridRun();
        }
        private async void SendGridRun()
        {
            string email = sendgrid_txt.Text;

            if (EmailValdate(email))
            {
                // 타이머 초기화 및 인증번호 생성
                _duration = 60;
                _auth_code = GetRandomCode();
                timer1.Stop();
                timer1 = new Timer();
                timer1.Tick += new EventHandler(CountDown);
                timer1.Interval = 1000;
                timer1.Start();

                await Task.Run(() => SpendToMailSendGrid(email));
            }
            else
            {
                MessageBox.Show("이메일을 제대로 확인해주세요.");
            }
        }

        private void SpendToMailSendGrid(string email)
        {
            // sendgrid
            // var apiKey = Environment.GetEnvironmentVariable("Variable"); // 환경 변수 설정 후 사용
            var apiKey = ConfigurationManager.AppSettings["SendGridKey"];  // app.config에 설정후 사용
            var client = new SendGridClient(apiKey);
            var from = new EmailAddress(ConfigurationManager.AppSettings["SendGridHost"], "HOST");
            var to = new EmailAddress(email, "USER");
            var subject = "Sending with SendGrid is Fun";
            var plainTextContent = $"인증 코드 : {_auth_code}";
            var htmlContent = "";
            //var htmlContent = "<strong>and easy to do anywhere, even with C#</strong>";
            var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);
            var response = client.SendEmailAsync(msg);
        }

        // twilo
        private void button1_Click(object sender, EventArgs e)
        {
            TwiloRun();
        }

        private async void TwiloRun()
        {
            string phone = phone_txt.Text;

            if (PhoneValidate(phone))
            {
                // 타이머 초기화 및 인증번호 생성
                _duration = 60;
                _auth_code = GetRandomCode();
                timer1.Stop();
                timer1 = new Timer();
                timer1.Tick += new EventHandler(CountDown);
                timer1.Interval = 1000;
                timer1.Start();

                await Task.Run(() => SpendSMSTwilo(phone));
            }
            else
            {
                MessageBox.Show("휴대폰 번호를 제대로 확인해주세요.(- 없이 숫자만)");
            }
        }

        private void SpendSMSTwilo(string phone)
        {
            // twilo
            try
            {
                string accountSid = ConfigurationManager.AppSettings["TwiloSID"]; // App.config
                string authToken = ConfigurationManager.AppSettings["TwiloToken"]; // App.config

                TwilioClient.Init(accountSid, authToken);

                var message = MessageResource.Create(
                    body: $"인증번호 : {_auth_code}",
                    from: new Twilio.Types.PhoneNumber(ConfigurationManager.AppSettings["TwiloHost"]), // App.config
                    to: new Twilio.Types.PhoneNumber($"+82{phone}")
                );
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        // gmail
        private void auth_btn_Click(object sender, EventArgs e)
        {
            GmailRun();
        }

        private async void GmailRun()
        {
            string email = email_txt.Text;

            if (EmailValdate(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;
            }
            else
            {
                MessageBox.Show("이메일을 제대로 확인해주세요.");
            }
        }
        private void sendGmailAsync(string email)
        {
            // smtp 초기화 및 설정
            MailMessage mailMessage = new MailMessage();

            // 보내는 사람 이메일
            // mailMessage.From = new MailAddress("전송하는 계정 주소", "표시 이름", System.Text.Encoding.UTF8);
            //mailMessage.From = new MailAddress(_email, "인증번호", System.Text.Encoding.UTF8);
            mailMessage.From = new MailAddress(ConfigurationManager.AppSettings["GmailID"]);
            // 받는 사람 이메일
            mailMessage.To.Add(email);
            // 비공개 참조 메일 주소
            // mailMessage.Bcc.Add("aaa@naver.com");
            // 제목
            mailMessage.Subject = "인증코드";
            // 메일 제목 인코딩
            // mailMessage.SubjectEncoding = System.Text.Encoding.UTF8;
            // 본문
            mailMessage.Body = $"인증 코드 : {_auth_code}";
            // 본문의 포맷에 따라 선택
            // mailMessage.IsBodyHtml = false;
            // 본문 인코딩 타입
            // mailMessage.BodyEncoding = System.Text.Encoding.UTF8;
            // 파일 첨부
            // mailMessage.Attachments.Add(new Attachment(new FileStream(@"D:\test.zip", FileMode.Open, FileAccess.Read), "test.zip"));
            // smtp 서버 주소
            SmtpClient SmtpServer = new SmtpClient("smtp.gmail.com");
            // STML 포트
            SmtpServer.Port = 587;
            // SSL 사용 여부
            SmtpServer.EnableSsl = true;
            SmtpServer.UseDefaultCredentials = false;
            SmtpServer.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
            // 보낼 이메일 아이디랑 비밀번호 입력
            // SmtpServer.Credentials = new System.Net.NetworkCredential("아이디", "비밀번호");
            SmtpServer.Credentials = new System.Net.NetworkCredential(ConfigurationManager.AppSettings["GmailID"], ConfigurationManager.AppSettings["GmailPW"]);

            SmtpServer.Send(mailMessage);
        }

        // 이메일 검증
        public bool EmailValdate(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])?";
            return Regex.IsMatch(email, pattern);
        }

        // 휴대폰 번호 검증
        private bool PhoneValidate(string phone)
        {
            string pattern = @"01[0-4]{1}[0-9]{3,4}[0-9]{4}";

            return Regex.IsMatch(phone, pattern);
        }
        // 인증번호 확인 버튼 클릭 이벤트
        private void auth_check_btn_Click(object sender, EventArgs e)
        {
            if(auth_txt.Text.Trim().Equals(_auth_code))
            {
                MessageBox.Show("인증 되었습니다");
                ResetTimerAndCode();
                new_password_txt.ReadOnly = false;
                new_password_txt.Focus();
            }
            else
            {
                MessageBox.Show("다시 확인해주세요");
            }
        }

        // 비밀번호 변경 버튼
        private void change_password_btn_Click(object sender, EventArgs e)
        {
            if (id_txt.Text.Trim() == "")
            {
                MessageBox.Show("아이디를 입력해주세요");
                id_txt.Focus();
                return;
            }
            if (email_txt.Text.Trim() == "")
            {
                MessageBox.Show("이메일을 입력해주세요");
                email_txt.Focus();
                return;
            }
            if (new_password_txt.Text.Trim() == "")
            {
                MessageBox.Show("비밀번호를 입력해주세요");
                new_password_txt.Focus();
                return;
            }
            MessageBox.Show("변경 완료");
        }

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

        // 랜덤 코드 생성
        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 ResetTimerAndCode()
        {
            timer1.Stop();
            timer1.Dispose();
            _auth_code = "";
        }
    }
}





-2. QR코드 비밀번호 찾기

  • 내부 인증 코드를 만들어서 그걸 QR로 다시 변화시켜서 띄워준다
  • ZXing nuget에서 설치
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using ZXing;

namespace popup
{
    public partial class Form4 : Form
    {
        private string _auth = null;

        public Form4()
        {
            InitializeComponent();
        }

        private void spend_auth_btn_Click(object sender, EventArgs e)
        {
            _auth = GetRandomCode();

            // instance a writer object
            var barcodeWrite = new BarcodeWriter
            {
                Format = BarcodeFormat.QR_CODE,
                Options =
                {
                    Width = 100,
                    Height = 100,
                    PureBarcode = true
                }
            };
            
            // write text and generate a 2-D barcode as a bitmap
            var bitmap = barcodeWrite
                .Write(_auth);
            pictureBox1.Image = bitmap;
        }

        private void check_auth_btn_Click(object sender, EventArgs e)
        {
            if (auth_txt.Text.Equals(_auth))
            {
                MessageBox.Show("성공");
                password_txt.ReadOnly = false;
                password_txt.Focus();
                return;
            }
            MessageBox.Show("다시확인해보세요");
        }

        private void change_password_btn_Click(object sender, EventArgs e)
        {
            if(!string.IsNullOrEmpty(id_txt.Text) && !string.IsNullOrEmpty(password_txt.Text))
            {
                MessageBox.Show("성공");
                return;
            }
            MessageBox.Show("아이디와 비밀번호를 제대로 작성해주십시오");
        }

        private void close_btn_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        // 랜덤 코드 생성
        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());
        }
    }
}



3. 느낀점

  • 로그인 폼 하나에 정말 다양한 도전을 해보았고 정말 다양한 기능이 있다는걸 느꼈다
  • web과는 다르지만 틀은 갖기에 재미있게 만들수 있었다
  • 전에 만든 학생관리에 비해서 다양한 API를 사용해볼 수 있는 기회가 되었다
profile
아직까지는 코린이!
post-custom-banner

0개의 댓글