SSOボタンを作成する方法–Flaskログインチュートリアル

公開: 2022-03-11

多くの場合、ユーザーがデータを保存したり、独自のプロファイルを作成したり、機密リソースへのアクセスを制限したりするために、アプリケーションにはログイン機能が必要です。 最新のアプリでは、ユーザーは、メールの確認、パスワードのリセット、多要素認証などの標準的なログイン関連機能を期待しています。 これらの機能は、必要ではありますが、正しく理解するのは簡単ではなく、通常、アプリの主な業務ではありません。

ユーザー側では、さらに別の電子メールとパスワードのペアを作成して記憶する必要があるため、長い登録プロセスを実行したくない場合があります。 適切なパスワードマネージャーがないと、ユーザーは同じパスワードを再利用する傾向があり、セキュリティの面でひどいものになります。

シングルサインオン(SSO)は、主にソーシャルメディアボタンを使用したログインとしてユーザーに知られていますが、この問題の解決策として考案されました。 ユーザーにとって、別の面倒な登録プロセスを経ないことは簡単でした。 企業にとって、ユーザーの摩擦を取り除くことは常に大きなメリットです。開発者にとっては、ログイン関連のすべての機能がIDプロバイダー(Facebook、Google、Twitterなど)に委任されるようになり、コードが少なくなりました。 アプリは、ユーザーIDを検証するジョブを実行するIDプロバイダーを単に信頼します。

SSOは通常、OpenId Connect(OIDC)またはSAMLプロトコルを利用しています。 SAMLは、主にエンタープライズアプリケーションで使用されます。 OIDCはOAuth2の上に構築され、FacebookやGoogleなどのソーシャルIDプロバイダーによって使用されます。この投稿では、OIDC/OAuth2プロトコルに焦点を当てます。

このFlaskログインチュートリアルでは、SimpleLoginとFacebookをIDプロバイダーとしてFlaskアプリケーションにSSOログインボタンを追加するためのステップバイステップガイドを作成します。 これは外部ライブラリを使用せずに実行できますが、OAuthの複雑さを単純化するために、OAuthプロバイダーを統合するライブラリであるRequests-OAuthlibを使用します。 SSOを最初から実装することに興味がある場合は、 SSOログインの実装–生の方法を確認してください。

この記事の最後に、次のページがあるFlaskアプリが必要です。

  • ログインボタンを備えたホームページ
  • ログインに成功すると、ユーザーは名前、メールアドレス、アバターなどの情報を見ることができるユーザー情報ページ

このチュートリアルのすべてのコードは、flask-social-login-exampleリポジトリにあります。

デモもここで入手できます。 Glitchでコードをリミックスしてください。

ステップ1:ブートストラップフラスコアプリ

flaskRequests-OAuthlibvirtualenvまたはpipenvを使用して環境を分離することもできます。

pipインストールフラスコrequests_oauthlib

app.pyと、ホームページにログインボタンを表示するルートを作成します。

 import flask app = flask.Flask(__name__) @app.route("/") def index(): return """ <a href="/login">Login</a> """ if __name__ == '__main__': app.run(debug=True)

このアプリを実行して、すべてが正常に機能していることを確認しましょう。

 python app.py

http:// localhost:5000を開くと、このページが表示されます。 完全なコードはstep1.pyにあります。

SimpleLoginでログインする

ステップ2:IDプロバイダーの資格情報

現在、数百(数千ではないにしても)のIDプロバイダーがあり、最も人気のあるプロバイダーはFacebook、Google、GitHub、Instagramです。 この投稿では、開発者に優しいことからSimpleLoginが選択されています。 ただし、同じコードがどのOAuth2IDプロバイダーでも機能します。 (免責事項:私はたまたまSimpleLoginの共同創設者であり、それが私の決定の要因であった可能性があります。)

SimpleLoginにアクセスし、アカウントをまだ持っていない場合は作成してから、[開発者]タブで新しいアプリを作成してください。

アプリの詳細ページで、AppIDとAppSecretをコピーして、可変環境に保存してください。 OAuthの用語では、クライアントとは実際にはサードパーティのアプリ、つまりアプリを意味します。 これらの値をコードに直接入れることもできますが、クレデンシャルを環境変数に保存することをお勧めします。 これは、12の要因の3番目の要因でもあります。

OAuth2設定

 export CLIENT_ID={your AppID} export CLIENT_SECRET={your AppSecret}

app.pyで、ファイルの上にこれらの行を追加して、 client idclient secretを取得してください。

 import os CLIENT_ID = os.environ.get("CLIENT_ID") CLIENT_SECRET = os.environ.get("CLIENT_SECRET")

次のステップで使用するapp.pyの上部にこれらのapp.pyも追加してください。 これらは、OAuthエンドポイントページにコピーすることもできます。

 AUTHORIZATION_BASE_URL = "https://app.simplelogin.io/oauth2/authorize" TOKEN_URL = "https://app.simplelogin.io/oauth2/token" USERINFO_URL = "https://app.simplelogin.io/oauth2/userinfo"

ここでSSLの設定について心配する必要はないので、 Requests-OAuthlibにプレーンHTTPを使用しても問題がないことを伝えましょう。

 # This allows us to use a plain HTTP callback os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

いつものように、このステップのコードはstep2.pyにあります。

ステップ3:ログインリダイレクト

ユーザーがログインボタンをクリックすると、次のようになります。

  1. ユーザーはIDログインプロバイダーの承認ページにリダイレクトされ、ユーザーが自分の情報をアプリと共有するかどうかを尋ねられます。
  2. ユーザーが承認すると、アプリがaccess tokenと交換するために使用するURLのcodeとともに、アプリのページにリダイレクトされます。このコードを使用すると、後でサービスプロバイダーからユーザー情報を取得できます。

したがって、2つのルートが必要です。ユーザーをIDプロバイダーにリダイレクトするloginルートと、 codeを受信してaccess tokenと交換するcallbackルートです。 コールバックルートは、ユーザー情報の表示も担当します。

 @app.route("/login") def login(): simplelogin = requests_oauthlib.OAuth2Session( CLIENT_ID, redirect_uri="http://localhost:5000/callback" ) authorization_url, _ = simplelogin.authorization_url(AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url) @app.route("/callback") def callback(): simplelogin = requests_oauthlib.OAuth2Session(CLIENT_ID) simplelogin.fetch_token( TOKEN_URL, client_secret=CLIENT_SECRET, authorization_response=flask.request.url ) user_info = simplelogin.get(USERINFO_URL).json() return f""" User information: <br> Name: {user_info["name"]} <br> Email: {user_info["email"]} <br> Avatar <img src="{user_info.get('avatar_url')}"> <br> <a href="/">Home</a> """

ログインボタンをクリックすると、次のフローが表示されます。 完全なコードは、GitHubのstep3.pyにあります。

SimpleLoginでログインしてユーザー情報を許可する

Facebookでログイン

Facebook、Google、Twitterのログインの設定は少し複雑で、SSLの設定や適切なスコープの選択などの追加の手順が必要です。 これらはこの記事の範囲を超えています。

洗練されたUIとは別に、Facebookの統合で最も難しいのは、新しいバージョンのFacebook SDKではローカルのプレーンHTTPが許可されていないため、HTTPSでWebアプリをローカルに提供する方法を見つけることかもしれません。 クイックHTTPSURLを取得するための無料ツールであるNgrokを使用することをお勧めします。

ステップ1:Facebookアプリを作成する

https://developers.facebook.comにアクセスして、新しいアプリを作成してください。

新しいアプリIDを作成する

次に、次の画面で「Facebookログインの統合」を選択します。

Facebookログインを統合する

ステップ2:FacebookOAuthクレデンシャル

左側の「設定/基本」をクリックし、アプリIDアプリシークレットをコピーします。 これらは実際にはOAuth client-idclient-secretです。

基本設定

client-idclient-secretを更新します。

 export FB_CLIENT_ID={your facebook AppId} export FB_CLIENT_SECRET={your facebook AppSecret}

AUTHORIZATION_BASE_URLとTOKEN_URLを更新します。

 FB_AUTHORIZATION_BASE_URL = "https://www.facebook.com/dialog/oauth" FB_TOKEN_URL = "https://graph.facebook.com/oauth/access_token"

ホームページ:

 @app.route("/") def index(): return """ <a href="/fb-login">Login with Facebook</a> """

ステップ3:ログインとコールバックのエンドポイント

アプリがngrok http 5000コマンドを使用してngrokの背後で提供される場合、現在のURLをngrokURLに設定する必要があります。

 # Your ngrok url, obtained after running "ngrok http 5000" URL = "https://abcdefgh.ngrok.io"

Facebookのログイン/設定、有効なOAuthリダイレクトURI設定にURLを必ず追加してください。

有効なOAuthリダイレクトURI

ユーザーの電子メールにアクセスするには、 scopeemailを追加する必要があります。

 FB_SCOPE = ["email"] @app.route("/fb-login") def login(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, redirect_uri=URL + "/fb-callback", scope=FB_SCOPE ) authorization_url, _ = facebook.authorization_url(FB_AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url)

Facebookはコンプライアンスの修正を必要とするため、 callbackルートはもう少し複雑です。

 from requests_oauthlib.compliance_fixes import facebook_compliance_fix @app.route("/fb-callback") def callback(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, scope=FB_SCOPE, redirect_uri=URL + "/fb-callback" ) # we need to apply a fix for Facebook here facebook = facebook_compliance_fix(facebook) facebook.fetch_token( FB_TOKEN_URL, client_secret=FB_CLIENT_SECRET, authorization_response=flask.request.url, ) # Fetch a protected resource, ie user profile, via Graph API facebook_user_data = facebook.get( "https://graph.facebook.com/me?fields=id,name,email,picture{url}" ).json() email = facebook_user_data["email"] name = facebook_user_data["name"] picture_url = facebook_user_data.get("picture", {}).get("data", {}).get("url") return f""" User information: <br> Name: {name} <br> Email: {email} <br> Avatar <img src="{picture_url}"> <br> <a href="/">Home</a> """

これで、[Facebookでログイン]をクリックすると、フロー全体を確認できるはずです。

Facebookプロセスでログイン

完全なコードはfacebook.pyにあります。

結論

おめでとうございます。SSOログインをFlaskアプリに正常に統合しました。

簡単にするために、このチュートリアルでは、クロスサイトリクエストフォージェリ攻撃から防御するために重要なスコープや状態などの他のOAuthの概念については触れていません。 また、この記事で取り上げられていないデータベースにユーザー情報を保存する必要があるかもしれません。

また、アプリは本番環境でhttpsで提供する必要があります。これは、Let'sEncryptを使用して今日非常に簡単に実行できます。

Happy OAuthing!