백엔드

google otp fast api 서버 적용

happy_life 2024. 4. 5. 20:04

이번 포스팅에서는 사용자 인증 보안을 강화하기 위해 google otp 를 적용하는 과정을 포스팅하려고 합니다.

먼저 google otp의 동작과정을 바탕으로 비동기, 동기 처리를 해야하는지를 판단하는 과정을 기록하고, 이후 fast api에 google otp를 적용하는 과정을 설명하려고 합니다.

 

 

1. google otp의 동작과정

1) Set Up

- server에서 otp 시크릿 키를 생성하고 google Authenticator 에 QR 코드를 생성합니다.

 

2) OTP Generation

 - user는 QR 코드를 바탕으로 키를 인증합니다. 이 과정은 서버가 아닌 다른 네트워크(다른 api 등)를 거치지 않고 local 적으로 동작합니다.

 

3) OTP Verification

 - user가 키를 인증하면, 서버가 이를 증명합니다. 이 또한 local적으로 동작합니다. 

 

 

 

2. google otp 비동기 async를 사용해야하는지에 대한 답

네트워크를 타거나, OS와 관련된 기능이 존재하지 않으므로, async를 사용하지 않아도 됩니다. 하지만 메서드 단위에서 I/O와 관련된 것들이 존재한다면 async를 사용하는 것으로 이점을 얻을 수 있습니다.

 

 

 

3. google otp 적용 과정

1. onetimepass 적용 vs pyotp

 

아래 사진에서 보듯, onetimepass는 2015

onetimepass/pyotp

 

 

2. otp_secret_key 발급하기

pyotp.random_base32()
#dddasdas

 

 

3. otp 인증 url 발급하기

totp = self.get_otp()
otp_url = totp.provisioning_uri(name="rerasdasd25@naver.com", issuer_name="risiasdX")


    def get_otp(self):
        otp_secret_key = config.OTP_SECRET_KEY
        totp = pyotp.TOTP(otp_secret_key)
        return totp

 

 

4. 프론트에서 생성한 qr코드로부터 얻은 6자리 QR 키를 인자로 받아 api 로직 처리

@Transactional(propagation=Propagation.REQUIRED)
    async def verify_otp(self, request: VerifyOtpRequest) -> VerifyOtpResponse:
        user_no = request.user_no
        input_otp = request.otp

        bo_user = await self.bo_user_repository.find_by_no(request.user_no)

        # user 가 DB에 없는 경우 Exception을 던진다. - 해킹 방지 코드
        if not bo_user:
            raise SignInFailedException()

        totp = self.get_otp()
        if totp.verify(input_otp):
            # session Id 만들기
            session_id = Provider.create_session_id()

            # request에 스키마 만들고 세션 update
            sign_in_schema = BOUserSchemaConverter.to_bo_user_sign_in_schema(user_no, session_id)
            await self.bo_user_query_repository.update_sid_by_no(sign_in_schema)

            # Response에 session 담기
            verify_otp_data = BOUserResponseConverter.to_verify_otp_response(session_id)
            return verify_otp_data

        # 인증 안된 경우 예외 처리
        raise OtpFailedException()