GoogleログインでFlaskアプリケーションを作成する

GoogleログインでFlaskアプリケーションを作成する

おそらく、さまざまなWebサイトでGoogle Loginのオプションを見たことがあるでしょう。 一部のサイトには、Facebook LoginGitHub Loginなどのオプションもあります。 これらすべてのオプションにより、ユーザーは既存のアカウントを利用して新しいサービスを使用できます。

この記事では、FlaskWebアプリケーションの作成について説明します。 アプリケーションでは、ユーザーは新しいアカウントを作成する代わりに、Google IDを使用してログインできます。 このユーザー管理方法には、多くの利点があります。 従来のユーザー名とパスワードの組み合わせを管理するよりも安全でシンプルになります。

basics of Pythonをすでに理解している場合、この記事はより簡単になります。 また、WebフレームワークとHTTPリクエストについて少し知っておくと役立ちますが、それは必ずしも必要ではありません。

この記事の終わりまでに、次のことができるようになります。

  • ユーザーがGoogleでログインできるFlask Webアプリケーションを作成します

  • Googleとやり取りするクライアント資格情報を作成します

  • Flaskアプリケーションでのユーザーセッション管理にFlask-Loginを使用する

  • OAuth 2およびOpenID Connect(OIDC)の理解を深める

以下のボックスをクリックして、この記事で作成するアプリケーションのコードを取得できます。

ユーザーにGoogleログインを使用する理由

個々のユーザーにプロファイルを持たせることができます。 または、特定のユーザーのみに機能を提供したい場合があります。 いずれの場合でも、アプリケーションと対話しているユーザーを知る必要があります。 言い換えると、ユーザーを認証し、独自の方法でユーザーを識別する必要があります。

従来の解決策は、一意のユーザー名と秘密のパスワードを使用することです。 アプリケーションはその情報を保存し、必要なときにそれを要求します。 ただし、このソリューションにはいくつかの欠点があります。

  • パスワードを安全に管理する必要があります。

  • アカウント関連の機能を実装する必要があります。

    • 二要素認証

    • パスワードのリセット

  • 悪意のあるログイン試行から保護する必要があります。

  • ユーザーはさらに別のユーザー名とパスワードを覚えておく必要があります。

ユーザーにGoogleログインを使用すると、そのすべての責任をユーザーにプッシュできます。 アプリケーションは、ユーザーが認証を受けるまで待機します。 次に、Googleはそのユーザーについてアプリケーションに通知します。 その時点で、アプリケーションに効果的にログインできます。

パスワードを保存する必要はありません。Googleはすべてのセキュリティを処理します。

アプリケーションがGoogleログインを使用する方法

OAuth 2OpenID Connect (OIDC)と呼ばれる2つの非常に人気のある重要な仕様があります。 OIDCはOAuth 2の上に構築されており、いくつかの新しいアイデアと概念が追加されています。

これらの仕様は、サードパーティアプリケーションが別のサービスから情報を取得する方法を定義します。 通常、これにはユーザーからの同意の取得が含まれます。 これを少し解凍するために、これがビルドしようとしているアプリケーションにどのように適用されるかを見てみましょう。

サードパーティのアプリケーションを作成しようとしています。これにより、ユーザーはGoogle Loginボタンを使用してログインできるようになります。 そのためには、Googleがアプリケーションについて知る必要があります。 幸いなことに、アプリケーションをGoogleのクライアントとして登録できます。

ユーザーがアプリケーションにアクセスしてGoogle Loginボタンを押すと、ユーザーをGoogleに送信できます。 そこから、Googleはユーザーがアプリケーションにメールやその他の情報を渡すことに同意することを確認する必要があります。 ユーザーが同意すると、Googleはアプリケーションに情報を送り返します。 その後、その情報を保存し、後で参照して、ユーザーを効果的にログインさせることができます。

OpenID Connectの詳細

ユーザーに代わって情報を要求するには、プロバイダーとも呼ばれる認証サーバーに対してclientになる必要があります。 これらの仕様を掘り下げて理解する最初のことは、多くの重複する用語と概念があることです。

そのため、サードパーティアプリケーション(クライアントとも呼ばれます)として、ユーザーに代わってプロバイダーから情報を取得する必要があります。 それを可能にする一連の手順があり、それらの手順は特定の順序で実行する必要があります。 そのため、handshakeflow、またはdanceと呼ばれるOAuth2とOpenIDConnectが聞こえることがあります。

これらの手順は、大まかに次のとおりです。

  1. サードパーティのアプリケーションをプロバイダーのクライアントとして登録します。

    • プロバイダーから一意のクライアント資格情報を受け取ります。

    • これらのクライアント認証情報を使用して、後でプロバイダーの認証(本人であることの証明)を行います。

  2. クライアントはプロバイダーのauthorizationURLにリクエストを送信します

  3. プロバイダーはユーザーに認証を要求します(本人であることを証明します)

  4. プロバイダーは、クライアントに代わって行動することに同意するようユーザーに要求します。

    • 通常、これには制限されたアクセスが含まれ、クライアントが何を求めているのかがユーザーに明らかにされます。

    • これは、場所や連絡先にアクセスするために携帯電話でアプリを承認する必要があるときのようなものです。

  5. プロバイダーはクライアントに一意の認証コードを送信します。

  6. クライアントは、認証コードをプロバイダーのtokenURLに送り返します。

  7. プロバイダーは、ユーザーに代わって他のプロバイダーURLで使用するクライアントトークンを送信します。

Note:上記の手順は、OAuth 2で定義されている認証コードフロー用です。

これらの手順には、これまでに述べた標準の両方が含まれます。 OpenID Connect(OIDC)はOA​​uth 2の上に構築されており、主に認証プロセスに関係するいくつかの追加機能と要件が追加されています。 上記のフローで説明した認証以外に、アプリケーションの重要なOIDCの概念はprovider configurationuserinfo endpointです。

provider configurationには、OAuth 2フローに使用する必要のある正確なURLなど、プロバイダーに関する情報が含まれています。 OIDCプロバイダーには、standardized fieldsを含むドキュメントを取得するために使用できる標準のURLがあります。

userinfo endpointは、OAuth 2フローを実行した後、ユーザーに関する情報を返します。 これには、彼らのメールと、アプリケーションで使用する基本的なプロファイル情報が含まれます。 このユーザー情報を取得するには、上記のフローの最後のステップで説明されているように、プロバイダーからトークンが必要です。

プロバイダー設定とユーザー情報エンドポイントを後で利用する方法の詳細が表示されます。

Googleクライアントの作成

Google Loginオプションを有効にする最初のステップは、アプリケーションをクライアントとしてGoogleに登録することです。 それを行う手順を見ていきましょう。

まず、Googleアカウントが必要になることに注意してください。 Gmailを使用している場合は、すでに持っています。

次に、Google developers credentials pageに移動します。

一度、あなたは彼らの利用規約に同意するように促されるかもしれません。 これらに同意する場合は、次のページのCreate credentialsボタンを押してください。 OAuth client IDのオプションを選択します。

Google create credentials screen shot

上部にあるWeb applicationオプションを選択します。 Nameフィールドにクライアントの名前を指定することもできます。 提供する名前は、ユーザーに代わって動作するアプリケーションに同意するときにユーザーに表示されます。

今のところ、Webアプリケーションをローカルで実行するので、Authorized JavaScript originshttps://127.0.0.1:5000に、Authorized redirect URIshttps://127.0.0.1:5000/login/callbackに設定できます。 これにより、ローカルのFlaskアプリケーションがGoogleと通信できるようになります。

最後に、Createを押して、client IDclient secretをメモします。 後で両方が必要になります。

独自のWebアプリケーションを作成する

ここで、学んだ知識を実際のWebアプリケーションを作成するために適用する楽しい部分について説明します。

目標を念頭に置いて始めましょう。 ユーザーが自分のGoogleアカウントでログインできるようにするアプリケーションを作成します。 そのアプリケーションは、メールアドレスなど、ユーザーに関する基本的な情報をGoogleから取得できる必要があります。 次に、アプリケーションは基本的なユーザー情報をデータベースに保存する必要があります。

ただし、最初に、使用するフレームワークとライブラリを見てみましょう。

フラスコ

Flaskは、軽量のWebフレームワークであり、自称microframeworkです。 URLのルーティングやHTTPリクエストの処理など、Webアプリケーションが実行する基本タスク用の組み込みツールが付属しています。

人気とシンプルさの両方の例としてFlaskを使用することにしました。 ただし、OAuth 2とOIDCについて学んだことはFlaskに固有のものではありません。 実際、OAuth 2とOIDCを簡単にするために使用するライブラリも、あらゆるPythonコードで使用できます。 言い換えると、いくつかの小さな変更を加えることで、ここで学んだことを選択して、選択した別のフレームワークに適用できます。

フラスコログイン

ユーザーの処理を容易にするために使用できるもう1つのツールは、user session managementを提供するflask_loginです。

このライブラリは、舞台裏でいくつかのことを行い、ユーザーを支援するツールを提供します。 つまり、ユーザーがログインしたときとログアウトしたときを知るためのユーティリティを提供します。 これは、ブラウザーCookie内のユーザーセッションを管理することにより行われます。

また、ユーザーのデータベースエントリの作成など、ユーザーのログインとログアウトも処理します。 ただし、コードの観点からは、すべてが非常に単純になります(すぐにわかります)。

OAuthLib

セキュリティ関連および標準準拠のコードに非常に当てはまる一般的なフレーズがあります。「車輪を再発明しないでください。」

OAuth 2とOpenID Connectの標準は複雑です。 RFCと仕様をご覧ください。 密集しています。 1つの間違いは、アプリケーションの脆弱性を開く可能性があることを意味します。

そのため、これらの標準を実装するためのコードを書くつもりはありません。 いくつかの非常に具体的な基準で選択されたPythonパッケージを使用します。

  1. 人気のある一般的に推奨されるライブラリです。 他の多くのパッケージがこのライブラリを内部的に使用しています。

  2. 非常にアクティブで、頻繁にバグにパッチを当てています。

  3. これは戦闘に強く、2012年から続いています。

このライブラリを使用して、Flask、Django、Pyramidなどにより密接に統合するWebフレームワーク固有のパッケージがあります。 ただし、ここで学習したコードをフレームワークに依存しないようにするには、このライブラリを派手なラッパーなしで直接使用します。

依存関係のインストール

生活を楽にするために使用するサードパーティの依存関係がいくつかあります。 これらの依存関係の概要は次のとおりです。

  • 典型的なWebアプリケーションのタスクを簡単にするWebフレームワーク(Flask)

  • ユーザーセッションを管理する頭痛のない方法(Flask-Login)

  • 戦闘で強化されたOIDCライブラリ(oauthlib

さらに、次のものを使用します。

  • ログインするユーザーに関する情報を保存するデータベース(SQLite)

  • GoogleにHTTPリクエストを送信するユーザーフレンドリーな方法(requests

  • ローカルでhttpsを使用して安全に実行できるようにする簡単な方法(pyOpenSSL)

SQLiteは標準のPythonライブラリの一部ですが、他のパッケージはそうではありません。 そのため、インストールする依存関係がいくつかあります。 とりあえず、このアプリケーションの作成を順を追って見ていきましょう。

まず、上記のサードパーティの依存関係をインストールする必要があります。 これを行うには、次の内容のrequirements.txtファイルを作成します。

requests==2.21.0
Flask==1.0.2
oauthlib==3.0.1
pyOpenSSL==19.0.0
Flask-Login==0.4.1

Note:他のバージョンのパッケージも機能する可能性がありますが、これらはこの記事の作成およびテスト中に使用されたバージョンです。

次に、Pythonのパッケージインストーラーであるpipを使用して、これらの依存関係をインストールできます。

Note:コンピューターにさまざまなPythonアプリケーションの依存関係をインストールする場合は、通常、仮想環境を使用することをお勧めします。 詳細については、Python Virtual Environments: A Primerを参照してください。

requirements.txtファイルからインストールするには、ターミナルで次のコマンドを実行します。

$ pip install -r requirements.txt

これでロックンロールの準備が整いました! コードを詳しく見てみましょう。

インポート、構成、およびセットアップ

いくつかの基本的なデータベース機能とユーザー管理をサポートするいくつかのファイルを追加することから始めます。 これらはセクションごとに説明されません。これは主に、Python databaseの実装の詳細に飛び込むことが、私たちの目標から気をそらすウサギの穴であるためです。

schema.sqlファイルは、データベースにユーザーテーブルを作成するSQLの一部です。 このファイルには、ユーザーごとに保存するフィールドが表示されます。

この次のファイルには、データベースから情報を格納および取得するUserクラスが含まれています。 名前、メール、プロフィール写真はすべてGoogleから取得されます。これについては、記事の後半で説明します。

上記のコードからdb.pyschema.sql、およびuser.pyファイルを作成した後、新しいapp.pyファイルを作成できます。 次のインポートを追加します。

# Python standard libraries
import json
import os
import sqlite3

# Third-party libraries
from flask import Flask, redirect, request, url_for
from flask_login import (
    LoginManager,
    current_user,
    login_required,
    login_user,
    logout_user,
)
from oauthlib.oauth2 import WebApplicationClient
import requests

# Internal imports
from db import init_db_command
from user import User

これらはすべて後で使用するため、現時点でそれぞれを理解することはそれほど重要ではありません。 app.pyの次の部分は、いくつかの構成です。

# Configuration
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)
GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration"
)

GoogleクライアントIDとクライアントシークレットを保存する方法は次のとおりです。これらは記事の前半で作成する必要があります。 これらはOIDCフローの後半で使用されます。

アプリケーションは、環境変数を読み取ってクライアントの資格情報を取得しようとします。 これには2つの理由があります。

  1. 別の認証情報を使用する場合、後でコードを変更する必要はありません。環境を更新するだけです。

  2. 誤って秘密の資格情報をGitHub(または別の公開リポジトリ)にコミットすることはできません。

多くの人が誤って秘密を公開リポジトリにコミットしており、かなり深刻なセキュリティリスクをもたらしています。 環境変数を使用して、それから保護することをお勧めします。

Tip:export GOOGLE_CLIENT_ID=your_client_idを使用して、LinuxbashターミナルおよびMacOS Xターミナルでクライアント資格情報を環境変数として設定できます(GOOGLE_CLIENT_SECRETの場合も同様)。

Windowsを使用している場合は、コマンドプロンプトでset GOOGLE_CLIENT_ID=your_client_idを使用できます。

または、couldで文字列を直接ここに貼り付けて、これらの変数に格納します。 However、クライアントシークレットはnotを共有するか、パブリックリポジトリにコミットする必要があります。 つまり、実際のクライアント資格情報をここに貼り付ける場合は、このファイルをチェックインしないように非常に注意してください。

最後に、グローバル変数と素朴なデータベース初期化ロジックを含むコードを以下に示します。 データベースの初期化以外のほとんどは、前述のFlask、Flask-Login、およびOAuthLibをセットアップする標準的な方法です。

# Flask app setup
app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY") or os.urandom(24)

# User session management setup
# https://flask-login.readthedocs.io/en/latest
login_manager = LoginManager()
login_manager.init_app(app)

# Naive database setup
try:
    init_db_command()
except sqlite3.OperationalError:
    # Assume it's already been created
    pass

# OAuth 2 client setup
client = WebApplicationClient(GOOGLE_CLIENT_ID)

# Flask-Login helper to retrieve a user from our db
@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)

WebApplicationClientoauthlibクライアントを初期化するために、すでにGoogleのクライアントIDを使用していることに注意してください。

Flask and Flask-Login will useである別の環境変数SECRET_KEYを作成して、Cookieやその他のアイテムに暗号で署名することができます。

Webアプリケーションエンドポイント

今、楽しいもののために。 Webアプリケーションの4つのエンドポイントを作成します。

  1. ホームページ用

  2. ユーザーログインプロセスを開始するための1つ

  3. ユーザーがログインした後にGoogleがリダイレクトするコールバック用

  4. ログアウト用

これらのエンドポイントは、アプリケーション上のさまざまなURLによって非常に創造的な名前で定義されます。

  1. ホームページ: /

  2. ログイン: /login

  3. ログインコールバック: /login/callback

  4. ログアウト: /logout

もちろん、後でページと機能を追加することもできます。 このアプリケーションの最終結果は、必要なものを追加するために完全に拡張可能になります。

これらのエンドポイントの次のすべてのコードをapp.pyファイルに追加します。 これらのエンドポイントの各コードを1つずつ見ていきましょう。

ホームページ

これは視覚的には派手なものではありませんが、ユーザーがログインしている場合に別の何かを表示するためのきちんとしたロジックを追加します ログインしていない場合は、Google Loginというリンクが表示されます。

リンクを押すと、それらが/loginエンドポイントにリダイレクトされ、ログインフローが開始されます。 ログインに成功すると、ホームページにユーザーのGoogleメールとGoogleの公開プロフィール写真の両方が表示されます。

さらに面倒なことをせずに、app.pyファイルにコードを追加し始めることができます。

@app.route("/")
def index():
    if current_user.is_authenticated:
        return (
            "

Hello, {}! You're logged in! Email: {}

" "

Google Profile Picture:

" 'Google profile pic
' 'Logout'.format( current_user.name, current_user.email, current_user.profile_pic ) ) else: return 'Google Login'

HTMLを文字列として返していることに注意してください。Flaskはこれを提供できます。 current_user.is_authenticatedは、Flask-Loginライブラリの素敵な追加です。 これは、アプリケーションを操作している現在のユーザーがログインしているかどうかを判断する簡単な方法です。 これにより、条件付きロジックを適用できます。 この場合、ユーザーがログインしている場合、ユーザーについて保存した情報が表示されます。

current_user.emailなどのcurrent_userオブジェクトの属性としてフィールドにアクセスするだけで、ユーザーのデータベースエントリからフィールドを取得できます。 これはFlask-Loginのもう1つの追加です。

ログイン

それでは、OAuth 2フローを見てみましょう。 上からのGoogle Loginボタンは、このエンドポイントにリダイレクトされます。 フローの最初のステップは、GoogleのOAuth 2認証エンドポイントがどこにあるかを把握することです。

OAuth 2とOpenID Connect(OIDC)によって定義されているものの間の境界線は、ここから曖昧になります。 前に説明したように、OIDCにはprovider configurationの標準エンドポイントがあり、これには一連のOAuth2およびOIDC情報が含まれています。 その情報を含むドキュメントは、あらゆる場所の標準エンドポイント.well-known/openid-configurationから提供されます。

GOOGLE_DISCOVERY_URLを定義した前のコードをコピーしたと仮定すると、Googleのプロバイダー構成を取得するための迅速で素朴な関数は次のとおりです。

def get_google_provider_cfg():
    return requests.get(GOOGLE_DISCOVERY_URL).json()

Tip:これをより堅牢にするには、GoogleのAPIが失敗を返し、有効なプロバイダー構成ドキュメントを返さない場合に備えて、GoogleAPI呼び出しにエラー処理を追加する必要があります。

必要なプロバイダー構成ドキュメントのフィールドは、authorization_endpointと呼ばれます。 これには、クライアントアプリケーションからGoogleでOAuth 2フローを開始するために使用する必要があるURLが含まれます。

次のコードを使用して、すべてのロジックをまとめることができます。

@app.route("/login")
def login():
    # Find out what URL to hit for Google login
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]

    # Use library to construct the request for Google login and provide
    # scopes that let you retrieve user's profile from Google
    request_uri = client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri=request.base_url + "/callback",
        scope=["openid", "email", "profile"],
    )
    return redirect(request_uri)

幸い、oauthlibを使用すると、Googleへの実際のリクエストが簡単になります。 すでにGoogleクライアントIDを付与した事前設定済みのclientを使用しました。 次に、Googleで使用するリダイレクトを指定しました。 最後に、GoogleにいくつかのOAuth 2scopesを要求しました。

各スコープは、個別のユーザー情報と考えることができます。 あなたの場合、ユーザーのメールとGoogleからの基本的なプロフィール情報を求めています。 もちろん、ユーザーはこの情報を提供することに同意する必要があります。

Note:openidは、ユーザーにログインさせることでユーザーを認証するOIDCフローを開始するようにGoogleに指示するために必要なスコープです。 OAuth 2は実際に認証の方法を標準化していないため、この場合のフローにはこれが必要です。

ログインコールバック

前のいくつかのエンドポイントよりも少し複雑なので、これを少しずつやってみましょう。

Googleの認証エンドポイントにリダイレクトすると、Google側で多くのことが起こります。

アプリケーションのログインエンドポイントは、ユーザーを認証して同意を求めるGoogleのすべての作業のジャンプポイントです。 ユーザーがGoogleにログインし、電子メールと基本プロファイル情報をアプリケーションと共有することに同意すると、Googleは固有のコードを生成してアプリケーションに送り返します。

念のため、前に読んだOIDCの手順を以下に示します。

  1. サードパーティのアプリケーションをプロバイダーのクライアントとして登録します。

  2. クライアントは、プロバイダーのauthorizationURLにリクエストを送信します。

  3. プロバイダーはユーザーに認証を要求します(本人であることを証明します)。

  4. プロバイダーは、クライアントに代わって行動することに同意するようユーザーに求めます。

  5. プロバイダーはクライアントに一意の認証コードを送信します

  6. クライアントは認証コードをプロバイダーのtokenURLに送り返します

  7. プロバイダーは、ユーザーに代わって他のURLで使用するクライアントトークンを送信します

Googleがその一意のコードを送信すると、アプリケーションのこのログインコールバックエンドポイントに送信されます。 したがって、最初のステップは、エンドポイントを定義し、そのcodeを取得することです。

@app.route("/login/callback")
def callback():
    # Get authorization code Google sent back to you
    code = request.args.get("code")

次に行うことは、そのコードをGoogleのtokenエンドポイントに送り返すことです。 Googleがクライアントの認証情報を確認すると、先ほど読んだuserinfoエンドポイントなど、ユーザーに代わって他のGoogleエンドポイントに対して認証できるトークンが返送されます。 あなたの場合、基本的なプロファイル情報を表示するように要求しただけなので、トークンでできるのはそれだけです。

まず、Googleのtokenエンドポイントが何であるかを理解する必要があります。 プロバイダー構成ドキュメントを再度使用します。

# Find out what URL to hit to get tokens that allow you to ask for
# things on behalf of a user
google_provider_cfg = get_google_provider_cfg()
token_endpoint = google_provider_cfg["token_endpoint"]

oauthlibは、この次のコードブロックで数回助けになります。 まず、トークン要求を作成する必要があります。 リクエストが作成されたら、requestsライブラリを使用して実際にリクエストを送信します。 次に、oauthlibは、もう一度、応答からトークンを解析するのに役立ちます。

# Prepare and send a request to get tokens! Yay tokens!
token_url, headers, body = client.prepare_token_request(
    token_endpoint,
    authorization_response=request.url,
    redirect_url=request.base_url,
    code=code
)
token_response = requests.post(
    token_url,
    headers=headers,
    data=body,
    auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
)

# Parse the tokens!
client.parse_request_body_response(json.dumps(token_response.json()))

ユーザーのプロフィール情報を取得するために必要なツールが用意できたので、Googleに問い合わせる必要があります。 幸い、OIDCはユーザー情報エンドポイントを定義し、特定のプロバイダーのURLはプロバイダー構成で標準化されています。 プロバイダー構成ドキュメントのuserinfo_endpointフィールドを確認することで、場所を取得できます。 次に、oauthlibを使用してトークンをリクエストに追加し、requestsを使用してトークンを送信できます。

# Now that you have tokens (yay) let's find and hit the URL
# from Google that gives you the user's profile information,
# including their Google profile image and email
userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
uri, headers, body = client.add_token(userinfo_endpoint)
userinfo_response = requests.get(uri, headers=headers, data=body)

旅の次のステップは、userinfoエンドポイントからの応答を解析することです。 Googleは、オプションのフィールドemail_verifiedを使用して、ユーザーがアカウントを作成しただけでなく、メールアドレスを確認してアカウントの作成を完了したことを確認します。 Googleが提供するセキュリティのもう1つのレイヤーであるため、この検証を条件付きでチェックすることは一般に安全です。

そうは言っても、それを確認し、ユーザーが検証されたとGoogleが言った場合、ユーザーの情報を解析します。 使用する4つの基本プロファイル情報は次のとおりです。

  1. sub:件名、Googleのユーザーの一意の識別子

  2. email:ユーザーのGoogleメールアドレス

  3. picture:Googleでのユーザーの公開プロフィール写真

  4. given_name:Googleでのユーザーの名前と名前

その解析はすべて、次のコードになります。

# You want to make sure their email is verified.
# The user authenticated with Google, authorized your
# app, and now you've verified their email through Google!
if userinfo_response.json().get("email_verified"):
    unique_id = userinfo_response.json()["sub"]
    users_email = userinfo_response.json()["email"]
    picture = userinfo_response.json()["picture"]
    users_name = userinfo_response.json()["given_name"]
else:
    return "User email not available or not verified by Google.", 400

このコールバックの最終手順は次のとおりです。

  1. Googleから取得した情報を使用してデータベースにユーザーを作成します

  2. ユーザーをログインしてユーザーセッションを開始します

  3. ユーザーをホームページに戻します(ここで、パブリックプロファイル情報を表示します)

これらの手順を実行するコードは次のとおりです。

# Create a user in your db with the information provided
# by Google
user = User(
    id_=unique_id, name=users_name, email=users_email, profile_pic=picture
)

# Doesn't exist? Add it to the database.
if not User.get(unique_id):
    User.create(unique_id, users_name, users_email, picture)

# Begin user session by logging the user in
login_user(user)

# Send user back to homepage
return redirect(url_for("index"))

そのため、ここで行っているのは、ユーザーがまだ存在しない場合に、ユーザーのデータベースに新しい行を作成することです。 次に、Flask-Loginを使用してセッションを開始します。

ログアウト

ログアウトエンドポイントは、最後のいくつかのエンドポイントよりもはるかに少ないコードです。 ログアウト機能を呼び出してホームページにリダイレクトするだけです。 完了しました。 ここにあります:

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("index"))

@login_requireddecoratorは、ここで言及することが重要です。 これはFlask-Loginツールボックスの別のツールであり、ログインしているユーザーのみがこのエンドポイントにアクセスできるようにします。 ログインしたユーザーのみが何かにアクセスする必要がある場合、これを使用できます。 この場合、ログインしているユーザーのみがログアウトできます。

アプリケーションをローカルでテストする

ローカルコンピューターでFlaskアプリケーションを実行して、app.pyに最終的なコードを追加することでログインフローをテストできます。

if __name__ == "__main__":
    app.run(ssl_context="adhoc")

ターミナルで次のコマンドを使用して、Flaskアプリケーションを実行できます。

$ python app.py

Note:単純なデータベース初期化ロジックのため、このコマンドを初めて実行すると、データベースが作成されます。 アプリを起動するには、同じコマンドagainを実行する必要があります。

Flaskは、開発サーバーを実行している端末に印刷する必要があります。 https://127.0.0.1:5000/である必要があります。

Flaskの開発サーバーはhttpsを使用してローカルでandを実行し、Googleとの暗号化された接続を確保していることに注意してください。 これは、上記のコードのapp.runに対するssl_context="adhoc"引数によって実現されます。 これには、パッケージPyOpenSSLがインストールされている必要があります。

欠点は、使用される証明書がその場で生成されることです。そのため、ブラウザでhttps://127.0.0.1:5000/にアクセスすると、接続が安全でないか、プライベートではないことを示す大きな警告画面が表示される可能性があります。 これらの警告は事実上無視できます。

警告画面を通過すると、Google Loginというボタンが1つ表示されます。 押すと、公式のGoogleログインに移動します。 ログインすると、「サードパーティアプリケーション」があなたのメールとプロフィール情報にアクセスすることに同意するように求められます。

同意すると、Flaskアプリケーションにリダイレクトされ、ページにGoogleメールと公開プロフィール写真が表示されます。 最後に、Logoutボタンを使用すると、ログアウトできます。

結論

ユーザーが既存のアカウントを使用してWebアプリケーションにログインできるようにすることには、多くの利点があります。 最も重要なことは、アカウント管理のセキュリティと複雑さをあなたの肩にかける必要がないことです。 これにより、2要素認証などの細かい点について心配することなく、空想の新しいWebアプリケーションを自由に作成できます。

この記事で作成したアプリケーションは、出発点として最適です。 以下のボックスをクリックして、コードを取得できます。

次のステップは次のことです。

  • データベースの初期化をやり直して、アプリケーションの実行とは別に実行する

  • 管理を容易にするために、PythonコードからHTML / CSSを分離します。

    • templatesを使用できます。

    • 静的ファイル(JSやCSSなど)from elsewhereをロードすることもできます。

  • クラウドでアプリケーションをホストする

  • ドメイン名を購入する

  • 実際のSSL証明書を使用して、その厄介な警告を取り除きます

この記事では、OAuth 2とOpenID Connectの基本について説明しました。 よく知られているPythonパッケージを使用して、ユーザーが既存のGoogleアカウントでログインできるWebアプリケーションを作成する方法を見てきました。 最も重要なことは、次のWebアプリケーションの優れた出発点として役立つサンプルコードがあることです。