코딩캠프/AI 웹개발 취업캠프

[AI 웹개발 취업캠프] 63Day - 프로젝트 14일차

고랑E 2023. 10. 19. 23:29
728x90

오늘은 로그인, 유저 조회를 구현해볼거다


로그인

 

생각 보다 진도가 너무 안나가서 ... 불안해진다.. ㅠㅠ

 

일단 단순히 DB에 있는 정보랑 비교해서 맞게 입력했다면 로그인 성공 여부를 구현해 보자

 

pydantic 을 이용해 로그인 정보를 벨리데이션 해준다.

 

schemas.py

class UserLogin(BaseModel):
    email: str
    password: str

 

로그인 절차는

1. email, password 를 받아오고

2. db에서  email를 찾는다
3. 없다면 오류를 보내고 있다면 비밀번호를 비교해준다

4. 비번도 맞으면 로그인 성공

 

main.py

# 위쪽에 get_user, verify_password 를 추가
from BE.crud import create_user, get_user, verify_password


@app.post("/login")
def login(user_login: UserLogin, db: Session = Depends(get_db)):
    user_in_db = get_user(db, user_login.email)
    if not user_in_db:
        raise HTTPException(status_code=400, detail="이메일 또는 비밀번호를 잘못 입력했습니다.")
    if not verify_password(user_in_db.password, user_login.password):
        raise HTTPException(status_code=400, detail="이메일 또는 비밀번호를 잘못 입력했습니다.")    
    return {"message":"로그인 되었습니다."}

 

crud.py

def get_user(db: Session, email: str):
    return db.query(User).filter(User.email == email).first()

def verify_password(hashed_password, plain_password):
    return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))

를 추가한다.

 

서버를 실행 하고 테스트 해보면

 

된다!!

 

이제 로그인 했을때 jwt로 access_token을 발급해보자

 

.env

ALGORITHM=
JWT_ACCESS_TOKEN_SECRET=
JWT_ACCESS_TOKEN_EXPIRRED_TIME=

를 추가해서 적당히 적는다 

 

알고리즘은 HS256 를 사용 할거니 알고리즘에 적는다.

 

jwt를 사용 하기 위해 

 

pip install python-jose

를 설치한다.

 

main.py

import os
from jose import jwt
from datetime import timedelta, datetime
from dotenv import load_dotenv

를 추가해서 jwt, dotenv 를 가져온다.

 

아래쪽에

load_dotenv('.env')

ALGORITHM = os.environ["ALGORITHM"]
JWT_ACCESS_TOKEN_SECRET = os.environ["JWT_ACCESS_TOKEN_SECRET"]
JWT_ACCESS_TOKEN_EXPIRRED_TIME = int(os.environ["JWT_ACCESS_TOKEN_EXPIRRED_TIME"])

를 추가해서 .env 정보를 불러온다.

 

JWT_ACCESS_TOKEN_EXPIRRED_TIME 은 숫자형으로 바꿔주기 위해 int() 를 사용해주고

 

엑세스 토큰을 만들어줄 함수를 만들어준다.

 

def create_access_token(data: dict):
    to_encode = data.copy()
    expire = datetime.utcnow() + timedelta(minutes= JWT_ACCESS_TOKEN_EXPIRRED_TIME)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode( to_encode, JWT_ACCESS_TOKEN_SECRET, algorithm=ALGORITHM )
    return encoded_jwt

 

이전에 만들었던 로그인 api 에 아래 부분을 추가해준다..

    access_token_expires_minutes = timedelta(minutes= JWT_ACCESS_TOKEN_EXPIRRED_TIME)

    access_token_payload ={
        'sub':user_in_db.email,
        'exp':datetime.utcnow() + access_token_expires_minutes,
        'iat':datetime.utcnow()
    }
    access_token = create_access_token(access_token_payload)

    return {"access_token": access_token}

 

서버를 실행하고 작동을 확인해본다.

 


유저 조회

간단하다.. ㅋㅋㅋㅋ

main.py

# 상단에는 get_user_info를 추가
from BE.crud import create_user, get_user, verify_password, get_user_info



@app.get("/users/{userId}")
def user_info(userId, db: Session = Depends(get_db)):
    user_info_db = get_user_info(db, userId)
    return user_info_db

crud.py

def get_user_info(db: Session, userId: int):
    user_info_db = db.query(User).filter(User.id == userId).first()
    return user_info_db

라고 생각한게 잘못이였다 ㅋㅋ 정보를 다 불러와서 필요한 정보만 가져올 필요가 있다.. ㅎㅎ

with_entities()를 사용하면 된다고 나와서 

db.query(User).filter(User.id == userId).with_entities(User.nickname, User.image).first()

으로 수정 후 조회 했는데.. ? 

네??

 

닉네임이랑 이메일을 뽑아서 보내주자.. ㅎㅎ

crud.py

def get_user_info(db: Session, userId: int):
    user_info_db = db.query(User).filter(User.id == userId).with_entities(User.nickname, User.image).first()
    nickname, image = user_info_db
    return {"nickname": nickname, "image": image}

 

하면 간단하게 아래처럼 정보를 불러올수있다.

여기서.. 없는  데이터를 조회했을때 문제가 발생한다..

 

500 와 오류 로그가 뿜뿜 해버린다 조회한 내용이 없을땐 None을 보내주자

 

crud.py

    if user_info_db is None:
        return None

부분을 추가해서

def get_user_info(db: Session, userId: int):
    user_info_db = db.query(User).filter(User.id == userId).with_entities(User.nickname, User.image).first()
    if user_info_db is None:
        return None
    nickname, image = user_info_db
    return {"nickname": nickname, "image": image}

이렇게 만들어준다.

후 이제 끝났나?

했지만 하나 더 있었다 ㅎㅎㅎ 숫자가 아니라 문자열이 들어왔을때를 처리를 안해줬다 ㅎㅎ

 

main.py

 

원래 코드가

@app.get("/users/{userId}")
def user_info(userId, db: Session = Depends(get_db)):
    user_info_db = get_user_info(db, userId)
    return user_info_db

에서  userId 에 타입을 명시해준다!! ㅎㅎ

@app.get("/users/{userId}")
def user_info(userId: int, db: Session = Depends(get_db)):
    user_info_db = get_user_info(db, userId)
    return user_info_db

 

그럼 오류로그 대신 422 로 알려준다

 

 

 

 

본 후기는 정보통신산업진흥원(NIPA)에서 주관하는 <AI 서비스완성! AI+웹개발 취업캠프 - 프론트엔드&백엔드> 과정 학습/프로젝트/과제 기록으로 작성되었습니다.