인증을 어떻게 처리할 것인가에 대해서 의견을 정하기위해 미뤄놨던 이메일 인증을 구현해보려고 한다.
Gmail의 SMTP(Simple Mail Transfer Protocol)를 이용해 이메일을 발송할거다.
우선 Gmail SMTP 설정 단계
- IMAP 사용
- 2단계 인증
- 앱 비밀번호
Gmail SMTP 설정
IMAP 사용
메일로 들어간다
https://mail.google.com/mail/u/1
우측 상단 설정 > 모든 설정 보기 를 눌러준다.
전달 및 POP/IMAP로 들어가준다.
왼쪽에 있던 사진을 오른쪽 사진처럼 IMAP 사용을 한다.
IMAP 사용, 자동 삭제 사용, IMAP 메일 수 제한하지 않음 후 변경사항 저장
IMAP 사용 빼고는 원하는대로 해도 된다.
2단계 인증 사용
우측 상단에 프로필을 누르고 Google 계정 관리 > 좌측 탭 - 보안
아래 내려보면 Google에 로그인하는 방법 > 2단계 인증
시작하기 > 계속
원하는 방식으로 인증 진행
사용 설정 완료
완료 하면 다음과 같은 화면이 나옵니다.
앱 비밀번호 생성
앱 비밀번호 생성할 이름을 아무거나?! 정해주고 만들기를 누릅니다.
그럼 앱 비밀번호가 aaaa bbbb cccc dddd 형식으로 생성됩니다.
꼭 복사 해두시고 메모 해두세요 생성했던 앱 비밀번호는 다시 볼 수 없습니다.
(새로 생성 하시면 되긴 합니다.)
설정 완료
Python 코드
이제 코드를 작성해볼까!!
fastapi-mail 패지키를 사용 해보자!!
패키지 설치
pip install fastapi-mail
깃허브에 올라온 예제를 이용해 이메일 발송까지 되는지 봐보자
https://github.com/sabuhish/fastapi-mail
.env
예시 코드에서 conf 부분을 env에서 불러오자
GMAIL_MAIL_SERVER=
GMAIL_MAIL_PORT=
GMAIL_MAIL_USERNAME=
GMAIL_MAIL_PASSWORD=
GMAIL_MAIL_FROM=
GMAIL_MAIL_FROM_NAME=
를 각 부분에 맞춰 작성한다.
main.py
# 상단에 fastapi-mail 관련 임포트
from fastapi_mail import FastMail, MessageSchema, ConnectionConfig, MessageType
# EmailSend 추가
from BE.schemas import UserCreate, UserLogin, UserUpdate, ModelCreate, EmailSend
.env에서 값 가져오기
GMAIL_MAIL_USERNAME = os.environ["GMAIL_MAIL_USERNAME"]
GMAIL_MAIL_PASSWORD = os.environ["GMAIL_MAIL_PASSWORD"]
GMAIL_MAIL_FROM = os.environ["GMAIL_MAIL_FROM"]
GMAIL_MAIL_SERVER = os.environ["GMAIL_MAIL_SERVER"]
GMAIL_MAIL_FROM_NAME = os.environ["GMAIL_MAIL_FROM_NAME"]
연결설정 변수에 저장
conf = ConnectionConfig(
MAIL_USERNAME = GMAIL_MAIL_USERNAME,
MAIL_PASSWORD = GMAIL_MAIL_PASSWORD,
MAIL_FROM = GMAIL_MAIL_FROM,
MAIL_PORT = 587,
MAIL_SERVER = GMAIL_MAIL_SERVER,
MAIL_FROM_NAME = GMAIL_MAIL_FROM_NAME,
MAIL_STARTTLS = True,
MAIL_SSL_TLS = False,
USE_CREDENTIALS = True,
VALIDATE_CERTS = True
)
api
@app.post("/send-mail")
async def simple_send(email: EmailSend):
html = """<p>Hi this test mail, thanks for using Fastapi-mail</p> """
message = MessageSchema(
subject = "Fastapi-Mail module",
recipients = [email.email],
body = html,
subtype = MessageType.html
)
fm = FastMail(conf)
await fm.send_message(message)
return JSONResponse(status_code=200, content={"message": "email has been sent"})
shemas.py
# 상단에 EmailStr 추가
from pydantic import BaseModel, EmailStr
class EmailSend(BaseModel):
email: EmailStr
이러고 테스트를 해보면
발송이 된다.
발송시간이 거의 2.5~3.5초 사이 걸리는거같다.. 흠.. 줄이는방법이 있을까.. 고민 해봐야할듯..
이메일 제목, 내용 부분을 수정하자
@app.post("/send-mail")
async def simple_send(email: EmailSend):
html = """
<div>
<b>※ 인증번호 요청에 따른 발신 전용 메일입니다.</b>
<br>
<br>
인증코드는 <b>CODE</b> 입니다.
</div>
"""
message = MessageSchema(
subject = "인증코드 발송",
recipients = [email.email],
body = html,
subtype = MessageType.html
)
fm = FastMail(conf)
await fm.send_message(message)
return JSONResponse(status_code=200, content={"message": "인증코드가 이메일로 발송되었습니다."})
의 결과가
이제 랜덤코드를 만들고 그걸 메일이랑 같이 보내보자!!
랜덤을 생성하기위한 여러가지가있지만 secrets 모듈에 있는 token_hex 또는 token_urlsafe 함수를 사용할 거다.
아래 코드로 수정하고 발송 테스트를 해보자
code = secrets.token_hex(3)
html = f"""
<div>
<b>※ 인증번호 요청에 따른 발신 전용 메일입니다.</b>
<br>
<br>
인증코드는 <b>{code}</b> 입니다.
</div>
"""
code = secrets.token_urlsafe(3)
html = f"""
<div>
<b>※ 인증번호 요청에 따른 발신 전용 메일입니다.</b>
<br>
<br>
인증코드는 <b>{code}</b> 입니다.
</div>
"""
의 차이가 난다 근데 뭔가 인증코드로 보기엔 token_urlsafe 함수가 더 좋은거같다
이메일 인증 모델
alembic 으로 디비에 마이그레이션 하는 코드를 작성해 보자
일단 email_auths 테이블을 만들어보자
alembic revision -m "create email_auths table"
다음과 같은 명령어로 마이그레이션 파일을 만들고 기본으로 작성된 코드에서 upgrade, downgrade 함수부분만 수정해주면된다.
email, code 컬럼을 사용 할거니까
def upgrade():
# email_auths 테이블
op.create_table(
'email_auths',
sa.Column('id', sa.BigInteger, primary_key=True),
sa.Column('email', sa.String(255), nullable=False),
sa.Column('code', sa.String(8), nullable=False),
)
def downgrade():
op.drop_table('email_auths')
코드를 수정해주고
터미널에 db 업그레이드 명령어를 입력해준다.
alembic upgrade head
db 확인해보면 잘 만들어졌다.
models.py
모델을 정의해주고
class EmailAuth(Base):
__tablename__ = "email_auths"
id = Column(BigInteger, primary_key=True, index=True)
email = Column(String(255), unique=True, index=True)
code = Column(String(8))
shemas.py
code 부분을 추가해준다.
class EmailSend(BaseModel):
email: EmailStr
code: str = None
main.py
# 상단에 email_code 추가
from BE.crud import create_user, get_user, verify_password, get_user_info, update_user_info, get_models, get_my_models, create_model, get_model, email_code
# 상단에 EmailSend 추가
from BE.schemas import UserCreate, UserLogin, UserUpdate, ModelCreate, EmailSend
api 쪽에서 db로 넘겨준다.
email.code = code
email_code(db, email)
crud.py
# 상단에 EmailAuth 추가
from BE.models import User, Model, EmailAuth
# 상단에 EmailSend 추가
from BE.schemas import UserCreate, UserUpdate, ModelCreate, EmailSend
이제 db에 넣어주는 코드를 작성해 보자 예전에 작성했던 회원가입, 모델 생성 코드랑 비슷하다
def email_code(db: Session, email: EmailSend):
email_auth_data = email.model_dump()
db_email_auth = EmailAuth(**email_auth_data)
db.add(db_email_auth)
db.commit()
db.refresh(db_email_auth)
return db_email_auth
로 코드를 작성하고 테스트를 해보자
기능 구현 끝~
본 후기는 정보통신산업진흥원(NIPA)에서 주관하는 <AI 서비스완성! AI+웹개발 취업캠프 - 프론트엔드&백엔드> 과정 학습/프로젝트/과제 기록으로 작성되었습니다.
'코딩캠프 > AI 웹개발 취업캠프' 카테고리의 다른 글
[AI 웹개발 취업캠프] 72Day - 프로젝트 23일차 (0) | 2023.11.01 |
---|---|
[AI 웹개발 취업캠프] 71Day - 프로젝트 22일차 (0) | 2023.10.31 |
[AI 웹개발 취업캠프] 69Day - 프로젝트 20일차 (0) | 2023.10.27 |
[AI 웹개발 취업캠프] 68Day - 프로젝트 19일차 (1) | 2023.10.26 |
[AI 웹개발 취업캠프] 67Day - 프로젝트 18일차 (0) | 2023.10.25 |