내가 계획한 웹사이트는 로그인 시에는 이메일이 유효한지 확인을 해야할 필요가 있다.
그래서 이메일을 보냈을 때, 이메일 본문의 링크를 클릭할 시 인증이 되는 기능을 만들고 싶었다.
다행히도 Firebase에는 GenerateEmailVerificationLinkAsync 메서드가 있었고,
슬프게도, 한두시간 이리저리 만져본 결과, 내 프로젝트에는 적용할 수 없다는 판정을 받았다.
왜냐하면 내 프로젝트는 계정을 두 개를 사용해야 했기 때문이다. 로그인용으로 하나, 재학생 인증용으로 학교 이메일(얘가 인증 보낼 메일 주소다) 하나를 사용해야 했다.
야속하게도(?) Firebase를 통해 전송하려면 보낼 대상의 이메일이 User로서 등록되어 있어야 하기에 그 외의 주소로는 보낼 수 없었다. 그러니까 재학생을 인증받는 것은 새로 등록해야만 가능하다.
그래서 아예 Firebase를 사용하지 않고 Gmail의 SMTP를 이용해(이 표현이 맞나 모르겠다) 메일을 보내기로 했다. 생성한 Verification링크를 지메일을 통해 보낼 수 있나 해봤지만, 실력이 부족해서 그런지 되는지는 잘 모르겠다. 그래서 방식을 바꿨다. 이메일에 난수를 포함하여 보내고, 페이지에 그 난수를 입력했을 때 동일한 경우에 인증됨을 식별하는 방법이다.
우선, 이메일 주소를 입력받고 올바른 형식인지 판별한다.
그리고 다음과 같이 작성했다.
public bool SendEmail(string email, string name, string uid) {
Random rand = new Random();
int randomNum = rand.Next(12345, 100000);
HttpContext.Session.SetInt32($"verify-{uid}", randomNum);
MailMessage message = new MailMessage {
// 송신자 주소
From = new MailAddress([보내는 사람의 이메일 주소]),
// 이메일 제목
Subject = "이메일을 인증하세요",
// 본문
Body = $"{name}님, 안녕하세요.<br/><br/>" +
"다음 번호를 통해 이메일 주소를 인증하세요. 또한 이 번호를 타인에게 노출하지 마세요<br/><br/>" +
$"{randomNum.ToString()}<br/><br/>" +
"이 주소의 인증을 요청하지 않았다면 이 이메일을 무시하셔도 됩니다.<br/>" +
"감사합니다.<br/><br/>",
IsBodyHtml = true,
DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure,
SubjectEncoding = Encoding.UTF8,
BodyEncoding = Encoding.UTF8
};
message.To.Add(new MailAddress(email));
using(SmtpClient smtp = new SmtpClient("smtp.gmail.com", 587)) {
smtp.Timeout = 5000;
smtp.UseDefaultCredentials = false;
smtp.EnableSsl = true;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.Credentials = new System.Net.NetworkCredential([보내는 사람의 이메일 주소], [앱 패스워드]);
try {
smtp.Send(message);
message.Dispose();
return true;
}
catch{
return false;
}
}
}
MailMessage의 IsBodyHtml을 true로 놓았기 때문에 html태그를 넣을 수 있다.
전송과정에는 using문을 사용했지만, smtp변수를 만들고 Host랑 포트를 넣어줘도 된다.
Host는 Gmail smtp주소인 "smtp.gmail.com"을, 포트번호는 587을 쓴다. SSL방식으로 보낸다면 465로 포트번호를 잡아야 한다. 근데 그냥 587쓰면 되는 것 같다.
Credentials에서 MailAddress로는 보내는 사람의 이메일 주소를 그대로 써주면 된다.
앱 패스워드가 살짝 까다롭다. 구글이 22년 5월부로 보안이 수준이 약한 앱의 액세스를 더이상 허용하지 않는다고 한다. 설정을 건드려볼려해도 아예 '이 설정은 사용할 수 없습니다'라고 못박아놓는다. 즉, 보내는 사람의 지메일 비밀번호 입력만으로는 메일을 보낼 수 없는 것이다. 앱 비밀번호라는 것을 만들어야 하는데, 간단하다.
- 송신자의 지메일 계정의 2단계 인증을 설정한다.
- 구글 계정 사이트에서 '앱 비밀번호' 페이지로 들어간다. (하단 사진 참고)
- '생성' 버튼을 눌러 키를 생성한다. 이 때 기기는 '기타'로 했다. 딱히 이름은 상관 없는 듯?
- 키는 창을 나가면 볼 수 없으므로 어딘가에 소중히 복사해놓는다.
앱 비밀번호까지 생성이 되었다면 잘 전송이 될 것이다.
SendEmail 메소드는 성공적으로 메일이 전송되었다면 true를 반환한다.
true값을 받으면 페이지가 다음과 같이 바뀐다.
이메일도 잘 도착했다.
메일 안의 인증코드를 입력하면 다음과 같은 화면으로 바뀐다.
사실 그렇게 어려운 것도 아닌데, 이거 가지고 몇 시간 헤맸다. 멍청한 나..ㅋ...
근데 사실 이게 맞는지는 잘 모르겠다. 뭐... 잘 보내졌으니 장땡인가?
'C# > ASP.NET Core' 카테고리의 다른 글
[Asp.net core] Firestore 저장할 때 자료형 주의할 거 (0) | 2023.05.07 |
---|---|
[Asp.net core] View에서 Controller로 데이터 전달 (전달할 것이 List일 때) (0) | 2023.05.07 |
[Asp.net core] Firebase Storage에 사진 업로드&다운로드 (0) | 2023.05.07 |
[Asp.net core] Firebase link 생성하고 이메일로 전송 (0) | 2023.05.06 |
[Asp.net core] Firebase 인증 구현기 (0) | 2023.05.05 |