Firebase로 사용자 인증

리전 ID

REGION_ID는 앱을 만들 때 선택한 리전을 기준으로 Google에서 할당하는 축약된 코드입니다. 일부 리전 ID는 일반적으로 사용되는 국가 및 주/도 코드와 비슷하게 표시될 수 있지만 코드는 국가 또는 주/도와 일치하지 않습니다. 2020년 2월 이후에 생성된 앱의 경우 REGION_ID.r이 App Engine URL에 포함됩니다. 이 날짜 이전에 만든 기존 앱의 경우 URL에서 리전 ID는 선택사항입니다.

리전 ID에 대해 자세히 알아보세요.

Firebase 인증을 사용하는 웹 서비스에 사용자 로그인 과정을 추가합니다.

본 가이드의 이 단계에서는 사용자를 인증한 후 사용자의 정보를 검색하여 표시하도록 웹 서비스를 업데이트합니다. 이 단계에서 사이트 요청 시간은 사용자별로 표시되는 것이 아니라 여전히 전체적으로 표시됩니다.

시작하기 전에

이 가이드의 이전 단계를 모두 완료했다면 이 섹션을 건너뜁니다. 그렇지 않으면 다음 중 하나를 완료합니다.

Firebase 인증 방법 추가

Firebase는 웹 서비스의 로그인 동작을 구성하는 데 사용할 수 있는 자바스크립트 메서드 및 변수를 제공합니다. 이 웹 서비스의 경우 로그아웃 기능, 가입 UI를 구성하는 변수, 사용자가 로그인 또는 로그아웃할 때의 변경사항을 제어하는 기능을 추가합니다.

인증 흐름에 필요한 동작을 추가하려면 static/script.js 파일의 현재 이벤트 리스너 메서드를 다음 코드로 바꿉니다.

window.addEventListener('load', function () {
  document.getElementById('sign-out').onclick = function () {
    firebase.auth().signOut();
  };

  // FirebaseUI config.
  var uiConfig = {
    signInSuccessUrl: '/',
    signInOptions: [
      // Comment out any lines corresponding to providers you did not check in
      // the Firebase console.
      firebase.auth.GoogleAuthProvider.PROVIDER_ID,
      firebase.auth.EmailAuthProvider.PROVIDER_ID,
      //firebase.auth.FacebookAuthProvider.PROVIDER_ID,
      //firebase.auth.TwitterAuthProvider.PROVIDER_ID,
      //firebase.auth.GithubAuthProvider.PROVIDER_ID,
      //firebase.auth.PhoneAuthProvider.PROVIDER_ID

    ],
    // Terms of service url.
    tosUrl: '<your-tos-url>'
  };

  firebase.auth().onAuthStateChanged(function (user) {
    if (user) {
      // User is signed in, so display the "sign out" button and login info.
      document.getElementById('sign-out').hidden = false;
      document.getElementById('login-info').hidden = false;
      console.log(`Signed in as ${user.displayName} (${user.email})`);
      user.getIdToken().then(function (token) {
        // Add the token to the browser's cookies. The server will then be
        // able to verify the token against the API.
        // SECURITY NOTE: As cookies can easily be modified, only put the
        // token (which is verified server-side) in a cookie; do not add other
        // user information.
        document.cookie = "token=" + token;
      });
    } else {
      // User is signed out.
      // Initialize the FirebaseUI Widget using Firebase.
      var ui = new firebaseui.auth.AuthUI(firebase.auth());
      // Show the Firebase login button.
      ui.start('#firebaseui-auth-container', uiConfig);
      // Update the login state indicators.
      document.getElementById('sign-out').hidden = true;
      document.getElementById('login-info').hidden = true;
      // Clear the token cookie.
      document.cookie = "token=";
    }
  }, function (error) {
    console.log(error);
    alert('Unable to log in: ' + error)
  });
});

사용자가 로그인 또는 로그아웃할 때 변경사항을 제어하는 onAuthStateChanged() 메서드는 사용자 ID 토큰을 쿠키로 저장합니다. 이 ID 토큰은 사용자가 로그인에 성공하면 Firebase가 자동으로 생성하는 고유한 토큰이며 서버에서 사용자를 인증하는 데 사용됩니다.

토큰을 사용하도록 웹 서비스 업데이트

다음으로, 고유한 Firebase ID 토큰을 사용하여 서버의 사용자를 확인한 다음 사용자의 데이터를 다시 출력할 수 있도록 토큰을 해독합니다.

Firebase ID 토큰을 사용하려면 다음 안내를 따르세요.

  1. main.py 파일의 root 메서드에서 토큰을 검색, 확인, 복호화합니다.

    from flask import Flask, render_template, request
    from google.auth.transport import requests
    from google.cloud import datastore
    import google.oauth2.id_token
    
    firebase_request_adapter = requests.Request()
    @app.route("/")
    def root():
        # Verify Firebase auth.
        id_token = request.cookies.get("token")
        error_message = None
        claims = None
        times = None
    
        if id_token:
            try:
                # Verify the token against the Firebase Auth API. This example
                # verifies the token on each page load. For improved performance,
                # some applications may wish to cache results in an encrypted
                # session store (see for instance
                # http://flask.pocoo.org/docs/1.0/quickstart/#sessions).
                claims = google.oauth2.id_token.verify_firebase_token(
                    id_token, firebase_request_adapter
                )
            except ValueError as exc:
                # This will be raised if the token is expired or any other
                # verification checks fail.
                error_message = str(exc)
    
            # Record and fetch the recent times a logged-in user has accessed
            # the site. This is currently shared amongst all users, but will be
            # individualized in a following step.
            store_time(datetime.datetime.now(tz=datetime.timezone.utc))
            times = fetch_times(10)
    
        return render_template(
            "index.html", user_data=claims, error_message=error_message, times=times
        )
    
  2. requirements.txt 파일에 필요한 모든 종속 항목이 있는지 확인합니다.

    Flask==3.0.0
    google-cloud-datastore==2.15.1
    google-auth==2.17.3
    requests==2.28.2
    

웹 서비스 테스트

가상 환경에서 로컬로 실행하여 웹 서비스를 테스트합니다.

  1. 프로젝트의 기본 디렉터리에서 다음 명령어를 실행하여 새 종속 항목을 설치하고 웹 서비스를 실행합니다. 로컬 테스트용으로 가상 환경을 설정하지 않은 경우 웹 서비스 테스트를 참조하세요.

    pip install -r requirements.txt
    python main.py
    
  2. 웹브라우저에 다음 주소를 입력하여 웹 서비스를 확인합니다.

    http://localhost:8080
    

웹 서비스 배포

로컬에서 인증이 작동하므로 웹 서비스를 App Engine에 다시 배포할 수 있습니다.

app.yaml 파일이 있는 프로젝트의 루트 디렉터리에서 다음 명령어를 실행합니다.

gcloud app deploy

모든 트래픽이 배포된 새 버전으로 자동 라우팅됩니다.

버전 관리에 대한 자세한 내용은 서비스 및 버전 관리를 참조하세요.

서비스 보기

브라우저를 빠르게 실행하고 https://PROJECT_ID.REGION_ID.r.appspot.com에서 웹 서비스에 액세스하려면 다음 명령어를 실행합니다.

gcloud app browse

다음 단계

사용자 인증을 설정했습니다. 이제 웹 서비스를 업데이트하여 인증된 사용자의 데이터를 맞춤설정하는 방법을 알아봅니다.