구글 소셜 로그인 구현하기

2024년 7월 1일 월요일

Today I Learned

날짜

2024년 7월 1일 월요일

내용

활성화 유저 체크

우리의 서비스(프로덕트 리뷰, ai, 리스트디자이너)를 사용하는 유저들을 탐색해서 저장하는 기능을 만들었다. 코어스크립트 활성화 여부, 앱블록 활성화여부를 확인하는 작업이라 이것저것 오류가 많이난다. 원인은 쇼피파이에서 테마를 가져와 우리의 앱블록(위젯)을 사용하는지 확인하는 과정에서 테마가 원하는 형태가 아닐 때가 많기 때문이다. 심지어 json 타입이아니라 string으로 올때조차 많은지라 온갖 예외처리가 덕지덕지 붙어있다.

브라우즈 부스터를 개발하고, 이 데이터에서 브라우즈부스터도 추가해주었다. 어느 순간 확인해보니 작동이 안되고있다! 또 뭐가 말썽인가 싶어 열심히 들여다 본 결과를 찾아냈다.. 로직이나 문법이 잘못된게 아니라 스키마를 최신하 안해줬다.. 진짜 별것도 아닌데, 오류 메시지도 뜨지 않고 멈춰서 찾기 힘들었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
active_user_data = ActiveUserData(
                product_review_corescript_active=before_data.product_review_corescript_active,
                product_review_corescript_updated_time=before_data.product_review_corescript_updated_time,
                product_review_appblock={},
                product_review_app_block_active=False,
                list_designer_active=False,
                list_designer_corescript_active=before_data.list_designer_corescript_active,
                list_designer_corescript_updated_time=before_data.list_designer_corescript_updated_time,
                list_designer_app_block={},
                list_designer_app_block_active=False,
                is_disable_browse_booster_corescript_active=before_data.browse_booster_corescript_active,
                browse_booster_corescript_updated_time=before_data.browse_booster_corescript_updated_time,
            )

ActiveUserData 에 브라우즈 부스터 관련된 스키마를 추가하지 않은채 할당하니 오류가 났었다..

구글 로그인 구현

아임리포트 개발의 첫 시작으로 구글 로그인 구현을 만들었다. 분명 예전에 만들었는데 왜 홀랑 까먹었는지.. 클라이언트에서 유저가 구글 로그인하면, 서버 쪽으로 “인가 코드”를 보내준다. 이 인가코드로 서버는 구글쪽에 access_token과 refresh_token을 요청한다. 유저 정보(이메일, 유저 이름 등)는 이 access_token으로 서버에 요청을 보내면 받을 수 있다. 유저 정보를 받아와 데이터를 서버에 저장하고나면, 다시 로그인 페이지로 리다이렉트 시키는데 이때 우리 서비스에서 고객을 특정하기 위해 사용하는 ‘service_id’ 를 parameter로 같이 보내준다.

프론트는 로그인 페이지에서 파라미터로 서비스 아이디가 있을 경우, 구글을 이용한 정보가 등록됐다고 생각해 로그인 요청을 보낸다. 서버는 서비스아이디로 유저 정보를 조회하고 있으면 로그인처리 해버린다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
@router.get("/google/callback")
def _google_sign_in(
    code: str,
    db: Session = Depends(get_db),
):
    """구글 로그인을 수행합니다."""
    url = "https://oauth2.googleapis.com/token"
    params = {
        "code": code,
        "client_id": GOOGLE_CLIENT_ID,
        "client_secret": GOOGLE_CLIENT_SECRET,
        "redirect_uri": f"{SERVER_URL}/auth/google/callback",
        "grant_type": "authorization_code",
    }
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
    }

    res = requests.post(url=url, params=params, headers=headers)
    res_json = res.json()

    google_access_token = res_json.get("access_token")
    user_info = get_google_user_info(google_access_token=google_access_token)
    db_user = get_user_by_login_id(login_id=user_info.get("email"), db=db)

    if not db_user:
        db_user = create_user(
            login_id=user_info.get("email"),
            login_password="",
            username=user_info.get("name"),
            email=user_info.get("email"),
            company="",
            thumbnail_url=user_info.get("picture"),
            db=db,
        )

    data = {
        "google_access_token": res_json.get("access_token"),
        "google_refresh_token": res_json.get("refresh_token"),
        "email": user_info.get("email"),
        "user_id": db_user.id,
    }

    create_google_login_account(data=data, db=db)

    return RedirectResponse(url=f"{FRONT_URL}/login?service_id={db_user.service_id}")

def get_google_user_info(
    google_access_token: str,
):
		"""Google에서 Access Token을 이용하여 사용자 정보를 가져옵니다."""
    url = "https://www.googleapis.com/oauth2/v1/userinfo"
    headers = {
        "Authorization": f"Bearer {google_access_token}",
    }
    res = requests.get(url=url, headers=headers)
    return res.json()

@router.get("/google")
def _google_login(
    service_id: str,
    db: Session = Depends(get_db),
) -> UserLoginGoogleOutput:
    """구글 로그인을 수행합니다."""
    service_access_token = create_service_access_token(
        service_id=service_id,
    )
    db_user = get_user_by_service_id(service_id=service_id, db=db)

    res = UserLoginGoogleOutput(
        login_id=db_user.login_id,
        username=db_user.username,
        email=db_user.email,
        company=db_user.company_name,
        thumbnail_url=db_user.thumbnail_url,
        service_id=db_user.service_id,
        service_refresh_token=db_user.service_refresh_token,
        access_token=service_access_token,
    )

    return res

구글 토큰도 만료시간이 있어서 주기적으로 연장해주어야 한다. 유저가 서비스에 접근하면 자동으로 로그인되도록 처리하고 싶은데, 어떻게 유저의 정보를 저장해둘지 + 구글 액세스 토큰을 언제 갱신할지 고민이 필요하다..

회고

브라우즈부스터를 만들다가 샵 액세스 코드 로직을 많이 바꾸었는데, 이 부분에서 자주 오류가 난다. 이번 스프린트가 끝나면 후딱 깔끔하게 리팩토링해야겠다.. 한번에 잘할껄