apeescape2.com
  • メイン
  • 製品の担当者とチーム
  • 仕事の未来
  • ヒントとツール
  • アジャイル
バックエンド

気が狂うことなくOAuth2をDjango / DRFバックエンドに統合する方法

私たちは皆そこにいました。あなたはAPIバックエンドに取り組んでおり、その進行状況に満足しています。最近、Minimum Viable Product(MVP)を完了し、テストはすべて合格しており、いくつかの新機能の実装を楽しみにしています。

次に、上司からメールが送信されます。「ちなみに、FacebookとGoogle経由でログインできるようにする必要があります。私たちのような小さなサイトのためだけにアカウントを作成する必要はありません。」

すごい。スコープクリープが再び発生します。



幸いなことに、OAuth 2はソーシャル認証およびサードパーティ認証(Facebook、Googleなどのサービスで使用される)の業界標準として登場したため、その標準の理解と実装に集中して、幅広い ソーシャル認証プロバイダー 。

OAuth2に慣れていない可能性があります。これが私に起こったとき、私はそうではありませんでした。

高レベルの設計ドキュメントテンプレート

OAuth2をDjango / DRFバックエンドに統合する

として Python開発者 、あなたの本能はあなたにつながるかもしれません ピップ 、PythonパッケージをインストールするためのPython Package Index(PyPA)推奨ツール。悪いニュースは、pipがOAuthを処理する278個のパッケージについて知っていることです。そのうち53個は特に言及しています。 Django 。オプションを調査するだけで1週間の作業になります。コードを書き始めてもかまいません。

このチュートリアルでは、OAuth2をDjangoまたはに統合する方法を学習します。 Django Rest Framework を使用して Python Social Auth 。この記事はDjangoRESTフレームワークに焦点を当てていますが、ここで提供される情報を適用して、他のさまざまな一般的なバックエンドフレームワークに同じものを実装できます。

OAuth2フローの概要

OAuth 2は、最初からWeb認証プロトコルとして設計されました。これは、ネット認証プロトコルとして設計された場合とまったく同じではありません。 HTMLレンダリングやブラウザリダイレクトなどのツールが利用可能であることを前提としています。

これは明らかにJSONベースのAPIの障害ですが、これを回避することができます。

従来のサーバー側のウェブサイトを作成しているかのようにプロセスを実行します。

サーバー側のOAuth2フロー

最初のステップは、アプリケーションフローの外部で完全に行われます。プロジェクトの所有者は、ログインが必要な各OAuth2プロバイダーにアプリケーションを登録する必要があります。

この登録中に、OAuth2プロバイダーに コールバックURI 、アプリケーションがリクエストを受信できるようになります。引き換えに、彼らは受け取ります クライアントキー そして クライアントシークレット 。これらのトークンは、ログイン要求を検証するために認証プロセス中に交換されます。

トークンは、サーバーコードをクライアントとして参照します。ホストはOAuth2プロバイダーです。 APIのクライアント向けではありません。

フローは、アプリケーションが「Facebookでログイン」や「Google+でサインイン」などのボタンを含むページを生成したときに始まります。基本的に、これらは単純なリンクに他ならず、それぞれが次のようなURLを指しています。

https://oauth2provider.com/auth? response_type=code& client_id=CLIENT_KEY& redirect_uri=CALLBACK_URI& scope=profile& scope=email

(注:読みやすくするために、上記のURIに改行が挿入されています。)

クライアントキーとリダイレクトURIを提供しましたが、シークレットは提供していません。代わりに、「プロファイル」スコープと「メール」スコープの両方に応答してアクセスする認証コードが必要であることをサーバーに通知しました。これらのスコープは、ユーザーに要求するアクセス許可を定義し、受け取るアクセストークンの承認を制限します。

受信すると、ユーザーのブラウザはOAuth2プロバイダーが制御する動的ページに移動します。 OAuth 2プロバイダーは、続行する前に、コールバックURIとクライアントキーが互いに一致することを確認します。その場合、フローはユーザーのセッショントークンに応じて一時的に分岐します。

ユーザーが現在そのサービスにログインしていない場合は、ログインするように求められます。ログインすると、アプリケーションのログインを許可する権限を要求するダイアログがユーザーに表示されます。

ユーザーが承認すると、OAuth2サーバーはユーザーを指定したコールバックURIにリダイレクトします。 認証コード クエリパラメータ内:GET https://api.yourapp.com/oauth2/callback/?code=AUTH_CODE。

認証コードは、有効期限が早く、1回限りのトークンです。サーバーは受信後すぐに向きを変え、認証コードとクライアントシークレットの両方を含めてOAuth2プロバイダーに別のリクエストを行う必要があります。

POST https://oauth2provider.com/token/? grant_type=authorization_code& code=AUTH_CODE& redirect_uri=CALLBACK_URI& client_id=CLIENT_KEY& client_secret=CLIENT_SECRET

この認証コードの目的は、上記のPOSTリクエストを認証することですが、フローの性質上、ユーザーのシステムを介してルーティングする必要があります。そのため、本質的に安全ではありません。

認証コードの制限(つまり、すぐに期限切れになり、一度しか使用できない)は、信頼されていないシステムを介して認証資格情報を渡す固有のリスクを軽減するためにあります。

サーバーからOAuth2プロバイダーのサーバーに直接行われるこの呼び出しは、OAuth2サーバー側のログインプロセスの重要なコンポーネントです。通話を制御するということは、通話がTLSで保護されていることがわかっているため、盗聴攻撃から通話を保護するのに役立ちます。

認証コードを含めると、ユーザーが明示的に同意を与えることが保証されます。ユーザーには表示されないクライアントシークレットを含めることで、このリクエストが、認証コードを傍受したユーザーのシステム上のウイルスやマルウェアから発信されないようにします。

すべてが一致する場合、サーバーは アクセストークン 、ユーザーとして認証されている間、そのプロバイダーに電話をかけることができます。

サーバーからアクセストークンを受信すると、サーバーはユーザーのブラウザをもう一度ログインしたばかりのユーザーのランディングページにリダイレクトします。アクセストークンはユーザーのサーバー側のセッションキャッシュに保持されるのが一般的です。サーバーは、必要なときにいつでも特定のソーシャルプロバイダーに電話をかけることができます。

アクセストークンをユーザーが利用できるようにしないでください。

私たちが掘り下げることができるより多くの詳細があります。

たとえば、Googleには 更新トークン これにより、アクセストークンの寿命が延びますが、Facebookは、短命のアクセストークンをより長命のアクセストークンと交換できるエンドポイントを提供します。ただし、このフローは使用しないため、これらの詳細は重要ではありません。

このフローは、RESTAPIにとって面倒です。フロントエンドクライアントに初期ログインページを生成させ、バックエンドにコールバックURLを提供させることもできますが、最終的には問題が発生します。アクセストークンを受け取ったら、ユーザーをフロントエンドのランディングページにリダイレクトする必要がありますが、そのための明確でRESTfulな方法はありません。

幸い、別のOAuth 2フローが利用可能であり、この場合ははるかにうまく機能します。

クライアント側のOAuth2フロー

このフローでは、フロントエンドがOAuth2プロセス全体の処理を担当します。これは一般にサーバー側のフローに似ていますが、重要な例外があります。フロントエンドはユーザーが制御するマシン上に存在するため、クライアントシークレットを委託することはできません。解決策は、プロセスのそのステップ全体を単純に排除することです。

サーバー側のフローと同様に、最初のステップはアプリケーションの登録です。

この場合、プロジェクト所有者は引き続きアプリケーションを登録しますが、Webアプリケーションとして登録します。 OAuth2プロバイダーは引き続き クライアントキー 、ただし、クライアントシークレットを提供しない場合があります。

フロントエンドは、OAuth 2プロバイダーが制御するWebページに誘導するソーシャルログインボタンをユーザーに提供し、ユーザーのプロファイルの特定の側面にアクセスするためのアプリケーションの許可を要求します。

今回はURLが少し異なります。

https://oauth2provider.com/auth? response_type=token& client_id=CLIENT_KEY& redirect_uri=CALLBACK_URI& scope=profile& scope=email

response_typeに注意してください今回のURLのパラメータはtokenです。

では、リダイレクトURIはどうですか?

これは、アクセストークンを適切に処理するために準備されたフロントエンド上の任意のアドレスです。

使用中のOAuth2ライブラリによっては、フロントエンドが実際に一時的にユーザーのデバイスでHTTPリクエストを受け入れることができるサーバーを実行する場合があります。その場合、リダイレクトURLの形式はhttp://localhost:7862/callback/?token=TOKENです。

OAuth 2サーバーはユーザーが承認した後にHTTPリダイレクトを返し、このリダイレクトはユーザーのデバイスのブラウザによって処理されるため、このアドレスは正しく解釈され、フロントエンドにトークンへのアクセスを許可します。

プログラミングにおける並行性とは

あるいは、フロントエンドは適切なページを直接実装することもできます。いずれにせよ、この時点で、フロントエンドはクエリパラメータの解析とアクセストークンの処理を担当します。

この時点から、フロントエンドはトークンを使用してOAuth2プロバイダーのAPIを直接呼び出すことができます。しかし、ユーザーはそれを本当に望んでいません。彼らはあなたのAPIへの認証されたアクセスを望んでいます。バックエンドが提供する必要があるのは、フロントエンドがソーシャルプロバイダーのアクセストークンをAPIへのアクセスを許可するトークンと交換できるエンドポイントだけです。

フロントエンドへのアクセストークンの提供はサーバー側のフローよりも本質的に安全性が低いのに、なぜこれを許可するのでしょうか。

クライアント側のフローにより、バックエンドのRESTAPIとユーザー向けのフロントエンドをより厳密に分離できます。バックエンドサーバーをリダイレクトURIとして指定することを厳密に妨げるものは何もありません。最終的な効果は、ある種のハイブリッドフローになります。

問題は、サーバーが適切なユーザー向けページを生成してから、何らかの方法でフロントエンドに制御を戻す必要があることです。

最近のプロジェクトでは、すべてのビジネスロジックを処理するフロントエンドUIとバックエンドの間で関心の分離を厳密に行うのが一般的です。これらは通常、明確に定義されたJSONAPIを介して通信します。上記のハイブリッドフローは、関心の分離を混乱させますが、バックエンドにユーザー向けのページを提供し、何らかのフローを設計してフロントエンドに戻るように制御します。

フロントエンドがアクセストークンを処理できるようにすることは、関心の分離を維持するための便利な手法です。侵害されたクライアントからのリスクがいくらか増加しますが、一般的にはうまく機能します。

このフローはフロントエンドにとって複雑に見えるかもしれません。フロントエンドチームがすべてを自分で開発する必要がある場合はそうです。ただし、両方 フェイスブック そして グーグル 最小限の構成でプロセス全体を処理するログインボタンをフロントエンドに含めることができるライブラリを提供します。

これがバックエンドでのトークン交換のレシピです。

クライアントフローでは、バックエンドはOAuth2プロセスからかなり分離されています。誤解しないでください。これは簡単な仕事ではありません。少なくとも次の機能をサポートする必要があります。

  • フロントエンドが提供したトークンが有効であることを確認するために、任意のランダムな文字列ではなく、少なくとも1つのリクエストをOAuth2プロバイダーに送信します。
  • トークンが有効な場合は、APIの有効なトークンを返します。それ以外の場合は、情報エラーを返します。
  • これが新規ユーザーの場合は、Userを作成しますそれらのモデルを作成し、適切に入力します。
  • これがUserのユーザーである場合モデルはすでに存在し、メールアドレスで照合して、ソーシャルログイン用に新しいアカウントを作成する代わりに、正しい既存のアカウントにアクセスできるようにします。
  • ユーザーがソーシャルメディアで提供した内容に基づいて、ユーザーのプロファイルの詳細を更新します。

幸いなことに、このすべての機能をバックエンドに実装するのは、予想よりもはるかに簡単です。

これが、わずか20行のコードでこれらすべてをバックエンドで機能させる方法の魔法です。 これは Python Social Auth ライブラリ(以降「PSA」)なので、両方を含める必要がありますsocial-auth-coreおよびsocial-auth-app-djangoあなたのrequirements.txtで。

また、文書化されているようにライブラリを構成する必要があります ここに 。わかりやすくするために、これは一部の例外処理を除外していることに注意してください。

この例の完全なコードは次のとおりです。 ここに 。

@api_view(http_method_names=['POST']) @permission_classes([AllowAny]) @psa() def exchange_token(request, backend): serializer = SocialSerializer(data=request.data) if serializer.is_valid(raise_exception=True): # This is the key line of code: with the @psa() decorator above, # it engages the PSA machinery to perform whatever social authentication # steps are configured in your SOCIAL_AUTH_PIPELINE. At the end, it either # hands you a populated User model of whatever type you've configured in # your project, or None. user = request.backend.do_auth(serializer.validated_data['access_token']) if user: # if using some other token back-end than DRF's built-in TokenAuthentication, # you'll need to customize this to get an appropriate token object token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}) else: return Response( {'errors': {'token': 'Invalid token'}}, status=status.HTTP_400_BAD_REQUEST, )

設定に必要なものがもう少しあります( 完全なコード )、これですべての設定が完了しました。

AUTHENTICATION_BACKENDS = ( 'social_core.backends.google.GoogleOAuth2', 'social_core.backends.facebook.FacebookOAuth2', 'django.contrib.auth.backends.ModelBackend', ) for key in ['GOOGLE_OAUTH2_KEY', 'GOOGLE_OAUTH2_SECRET', 'FACEBOOK_KEY', 'FACEBOOK_SECRET']: # Use exec instead of eval here because we're not just trying to evaluate a dynamic value here; # we're setting a module attribute whose name varies. exec('SOCIAL_AUTH_{key} = os.environ.get('{key}')'.format(key=key)) SOCIAL_AUTH_PIPELINE = ( 'social_core.pipeline.social_auth.social_details', 'social_core.pipeline.social_auth.social_uid', 'social_core.pipeline.social_auth.auth_allowed', 'social_core.pipeline.social_auth.social_user', 'social_core.pipeline.user.get_username', 'social_core.pipeline.social_auth.associate_by_email', 'social_core.pipeline.user.create_user', 'social_core.pipeline.social_auth.associate_user', 'social_core.pipeline.social_auth.load_extra_data', 'social_core.pipeline.user.user_details', )

urls.pyでこの関数にマッピングを追加すれば、準備は完了です。

その魔法はどのように機能しますか?

Python Social Authは、非常にクールで非常に複雑な機械です。認証と任意のアクセスへのアクセスを処理することは完全に幸せです 数十のソーシャル認証プロバイダー 、そしてそれは以下を含む最も人気のあるPythonウェブフレームワークで動作します Django 、 フラスコ 、 ピラミッド 、 CherryPy 、および WebPy 。

ほとんどの場合、上記のコードは非常に標準的なDjango RESTフレームワーク(DRF)関数ベースのビューです。urls.pyでマップしたパスでPOSTリクエストをリッスンします。そして、期待する形式でリクエストを送信すると仮定すると、Userを取得します。オブジェクト、またはNone。

Userを取得した場合オブジェクト。プロジェクトの他の場所で構成したモデルタイプであり、すでに存在している場合と存在していない場合があります。 PSAはすでにトークンの検証、ユーザーの一致が存在するかどうかの識別、必要に応じてユーザーの作成、ソーシャルプロバイダーからのユーザーの詳細の更新を処理しました。

ユーザーがソーシャルプロバイダーのユーザーからあなたのユーザーにマッピングされ、既存のユーザーに関連付けられる方法の正確な詳細は、SOCIAL_AUTH_PIPELINEによって指定されます。上で定義されています。これがどのように機能するかについて学ぶことはまだたくさんありますが、それはこの投稿の範囲外です。あなたはそれについてもっと読むことができます ここに 。

魔法の重要な部分は@psa()です。ビューのデコレータ。requestに一部のメンバーを追加します。ビューに渡されるオブジェクト。私たちにとって最も興味深いのはrequest.backendです(PSAにとって、バックエンドは任意のソーシャル認証プロバイダーです)。

適切なバックエンドが選択され、requestに追加されましたbackendに基づくオブジェクトビューへの引数。URL自体が入力されます。

node jsWebアプリケーションフレームワーク

backendを取得したらオブジェクトが手元にある場合は、アクセスコードを指定して、そのプロバイダーに対して認証することができます。それがdo_authです方法。これにより、SOCIAL_AUTH_PIPELINE全体が使用されます。設定ファイルから。

パイプラインは、拡張するとかなり強力なことを実行できますが、デフォルトの組み込み機能だけで、必要なすべてのことをすでに実行しています。

その後、通常のDRFコードに戻ります。有効なUserを取得した場合オブジェクトの場合、適切なAPIトークンを非常に簡単に返すことができます。有効なUserを取得できなかった場合オブジェクトを戻すと、エラーが発生しやすくなります。

この手法の欠点の1つは、エラーが発生した場合にエラーを返すのは比較的簡単ですが、具体的に何が悪かったのかについて多くの洞察を得るのが難しいことです。 PSAは、サーバーが問題の内容について返した可能性のある詳細をすべて飲み込みます。

繰り返しになりますが、適切に設計された認証システムの性質上、エラーの原因についてかなり不透明です。ログイン試行後にアプリケーションがユーザーに「無効なパスワード」と通知した場合、それは「おめでとうございます!有効なユーザー名を推測しました。」

自分で転がしてみませんか?

一言で言えば:拡張性。まったく同じ方法でAPI呼び出しでまったく同じ情報を必要とする、または返すソーシャルOAuth2プロバイダーはほとんどありません。ただし、あらゆる種類の特殊なケースと例外があります。

すでにPSAを設定した後で新しいソーシャルプロバイダーを追加することは、設定ファイルの数行の構成の問題です。コードを調整する必要はまったくありません。 PSAはそれらすべてを抽象化するため、独自のアプリケーションに集中できます。

いったいどうやってこれをテストするのですか?

良い質問! unittest.mockライブラリの奥深くにある抽象化レイヤーの下に埋め込まれたAPI呼び出しをモックアウトするのには適していません。モックへの正確なパスを見つけるだけでもかなりの努力が必要です。

代わりに、PSAはRequestsライブラリの上に構築されているため、優れたものを使用します 反応 HTTPレベルでプロバイダーをモックアウトするライブラリ。

テストの完全な説明はこの記事の範囲を超えていますが、テストのサンプルが含まれています ここに 。 mockedがあることに注意する特定の関数コンテキストマネージャーとSocialAuthTestsクラス。

PSAに手間のかかる作業を任せます。

OAuth2プロセスは詳細で複雑であり、固有の複雑さがたくさんあります。幸いなことに、可能な限り簡単な方法で処理するための専用ライブラリを導入することで、その複雑さの多くを回避することができます。

Python SocialAuthはその点で素晴​​らしい仕事をしています。クライアント側の暗黙的なOAuth2フローを利用して、わずか25行のコードでシームレスなユーザー作成とマッチングを実現するDjango / DRFビューを示しました。それはそれほど粗末ではありません。

JavaScriptの未来を見る

バックエンド

JavaScriptの未来を見る
テックインフルエンサーの領域内

テックインフルエンサーの領域内

製品の担当者とチーム

人気の投稿
Brexitが金融サービスセクターに与える影響
Brexitが金融サービスセクターに与える影響
マイクロサービス入門:Dropwizardチュートリアル
マイクロサービス入門:Dropwizardチュートリアル
IoT開発の開始:ESP8266Arduinoチュートリアル
IoT開発の開始:ESP8266Arduinoチュートリアル
効果的なランディングページをデザインする方法
効果的なランディングページをデザインする方法
売上予測とは?
売上予測とは?
 
Azureチュートリアル:Azure Machine LearningStudioを使用したガソリン価格の予測
Azureチュートリアル:Azure Machine LearningStudioを使用したガソリン価格の予測
挑戦的なM&A市場で最大の価値のためにビジネスを売る
挑戦的なM&A市場で最大の価値のためにビジネスを売る
Rでデータの変更を後押し
Rでデータの変更を後押し
第11章破産:それは何であり、次に何が起こるか?
第11章破産:それは何であり、次に何が起こるか?
生成的敵対的ネットワークを使用してランダムノイズからデータを作成する
生成的敵対的ネットワークを使用してランダムノイズからデータを作成する
人気の投稿
  • 設計上の制約とは
  • データ視覚化ソフトウェアとは
  • 請負業者の時給と給与
  • javascriptはタイムスタンプを日付に変換します
  • 子供向けのアプリを作成する方法
カテゴリー
投資家と資金調達 計画と予測 ヒントとツール 設計プロセス 技術 プロジェクト管理 革新 デザイナーライフ その他 プロセスとツール

© 2021 | 全著作権所有

apeescape2.com