web-dev-qa-db-ja.com

passport.js RESTful認証

Passport.jsを使用して、WebインターフェースではなくRESTful APIを介して、認証(ローカルおよびFacebookなど)をどのように処理しますか?

具体的な懸念事項は、コールバックからRESTfulレスポンス(JSON)へのデータの受け渡しと、典型的なres.send({data:req.data})の使用、Facebookにリダイレクトする初期/ loginエンドポイントのセットアップ(/ loginはできません)これはJSON応答ではないため、AJAXを介してアクセスされます-これは、コールバックを使用したFacebookへのリダイレクトです。

https://github.com/halrobertson/test-restify-passport-facebook が見つかりましたが、理解するのに苦労しています。

さらに、passport.jsはどのように認証資格情報を保存しますか?サーバー(またはサービスですか?)はMongoDBによってサポートされており、資格情報(ログインおよびpwのソルトハッシュ)が格納されると予想されますが、passport.jsにこのタイプの機能があるかどうかはわかりません。

155
ryanrhee

ここでは多くの質問がありますが、質問はNodeおよびpassport.jsのコンテキストで質問されますが、実際の質問は特定のテクノロジーでこれを行う方法よりもワークフローに関するものです。

セキュリティを強化するために少し変更した@Keithサンプルセットアップを使用しましょう。

  • https://example.comのWebサーバーは、単一ページのJavascriptクライアントアプリを提供します
  • https://example.com/apiのRESTful Webサービスは、リッチクライアントアプリにサーバーサポートを提供します
  • Nodeおよびpassport.jsに実装されたサーバー。
  • サーバーには、「users」テーブルを持つデータベース(あらゆる種類)があります。
  • ユーザー名/パスワードとFacebook Connectが認証オプションとして提供されます
  • リッチクライアントはRESTリクエストをhttps://example.com/apiにします
  • https://example.com/apiのWebサービスを使用するが、https://example.comのWebサーバーについては知らない他のクライアント(たとえば、電話アプリ)が存在する場合があります。

セキュアHTTPを使用していることに注意してください。これは、パスワードや認証トークンなどの機密情報がクライアントとサーバー間で渡されるため、公開で利用可能なサービスには必須です。

ユーザー名/パスワード認証

最初にプレーンな古い認証がどのように機能するかを見てみましょう。

  • ユーザーはhttps://example.comに接続します
  • サーバーは、初期ページをレンダリングする豊富なJavascriptアプリケーションを提供します。ページ内にログインフォームがあります。
  • このシングルページアプリの多くのセクションには、ユーザーがログインしていないため、データが入力されていません。これらのセクションにはすべて、「ログイン」イベントのイベントリスナーがあります。これはすべてクライアント側のものであり、サーバーはこれらのイベントを認識しません。
  • ユーザーがログイン名とパスワードを入力して送信ボタンを押すと、JavaScriptハンドラーがトリガーされ、クライアント側変数にユーザー名とパスワードが記録されます。次に、このハンドラーは「ログイン」イベントをトリガーします。繰り返しますが、これはすべてクライアント側のアクションであり、資格情報はまだサーバーに送信されていません.
  • 「ログイン」イベントのリスナーが呼び出されます。これらのそれぞれは、https://example.com/apiでRESTful APIに1つ以上のリクエストを送信して、ページに表示するユーザー固有のデータを取得する必要があります。 Webサービスに送信するすべてのリクエストには、おそらくHTTP Basic 認証の形式のユーザー名とパスワードが含まれます。これは、RESTfulであるサービスが1つのリクエストからクライアントの状態を維持できないためです。次。 Webサービスは安全なHTTP上にあるため、パスワードは送信中に安全に暗号化されます。
  • https://example.com/apiのWebサービスは、それぞれ認証情報を含む一連の個別のリクエストを受け取ります。各リクエストのユーザー名とパスワードは、ユーザーデータベースと照合され、見つかった場合、リクエストされた関数が実行され、データがJSON形式でクライアントに返されます。ユーザー名とパスワードが一致しない場合、エラーは401 HTTPエラーコードの形式でクライアントに送信されます。
  • クライアントにリクエストごとにユーザー名とパスワードを送信させる代わりに、ユーザー名とパスワードを取得してトークンで応答する「get_access_token」関数を使用できます。それに関連付けられた日付。これらのトークンは、各ユーザーとともにデータベースに保存されます。その後、クライアントは後続のリクエストでアクセストークンを送信します。アクセストークンは、ユーザー名とパスワードの代わりにデータベースに対して検証されます。
  • 電話アプリなどの非ブラウザクライアントアプリケーションは上記と同じことを行い、ユーザーに資格情報の入力を求め、Webサービスへのすべての要求で資格情報(またはそれらから生成されたアクセストークン)を送信します。

この例からの重要なポイントは、RESTful Webサービスでは、すべてのリクエストで認証が必要なことです

このシナリオで追加のセキュリティ層を使用すると、ユーザー認証に加えてクライアントアプリケーションの承認が追加されます。たとえば、すべてのWebサービスを使用するWebクライアント、iOSおよびAndroidアプリがある場合、認証されたユーザーが誰であるかに関係なく、特定のリクエストのクライアントが3つのうちどれであるかをサーバーに知らせることができますです。これにより、Webサービスが特定の機能を特定のクライアントに制限できるようになります。これについては、APIキーとシークレットを使用できます。 this answer を参照してください。

Facebook認証

Facebook経由のログインにはサードパーティであるFacebook自体があるため、上記のワークフローはFacebook接続では機能しません。ログイン手順では、ユーザーがFacebookのWebサイトにリダイレクトされる必要があり、そこでは資格情報が当社の制御外で入力されます。

それでは、物事がどのように変化するかを見てみましょう。

  • ユーザーはhttps://example.comに接続します
  • サーバーは、初期ページをレンダリングする豊富なJavascriptアプリケーションを提供します。ページには、「Facebookでログイン」ボタンを含むログインフォームがあります。
  • ユーザーは「Facebookでログイン」ボタンをクリックします。これは、(たとえば)https://example.com/auth/facebookにリダイレクトする単なるリンクです。
  • https://example.com/auth/facebookルートはpassport.jsによって処理されます( documentation を参照)
  • ユーザーに表示されるのは、ページが変更され、Facebookアプリケーションでログインし、Webアプリケーションを認証する必要があるページにいるということだけです。これは完全に私たちの管理外です。
  • ユーザーはFacebookにログインし、アプリケーションに許可を与えるため、Facebookはpassport.jsセットアップで構成したコールバックURLにリダイレクトします。これは documentation の例に従ってhttps://example.com/auth/facebook/callback
  • https://example.com/auth/facebook/callbackルートのpassport.jsハンドラーは、Facebookのアクセストークンと、ユーザーの電子メールアドレスを含むFacebookからのユーザー情報を受け取るコールバック関数を呼び出します。
  • この電子メールを使用して、データベース内でユーザーを特定し、Facebookアクセストークンを保存できます。
  • Facebookコールバックで最後に行うことは、リッチクライアントアプリケーションにリダイレクトすることですが、今回は、ユーザーが使用できるようにクライアントにユーザー名とアクセストークンを渡す必要があります。これにはいくつかの方法があります。たとえば、サーバー側のテンプレートエンジンを介してページにJavascript変数を追加したり、この情報とともにCookieを返すことができます。 (最初に提案したように、URLでこのデータを渡す際のセキュリティ問題を指摘してくれた@RyanKimberに感謝します)。
  • そのため、単一ページのアプリをもう一度起動しますが、クライアントにはユーザー名とアクセストークンがあります。
  • クライアントアプリケーションは、「ログイン」イベントをすぐにトリガーし、アプリケーションのさまざまな部分がWebサービスから必要な情報を要求できるようにします。
  • https://example.com/apiに送信されるすべてのリクエストには、認証用のFacebookアクセストークン、またはREST AP​​Iの「get_access_token」関数を介してFacebookのトークンから生成されたアプリケーション独自のアクセストークンが含まれます。
  • ブラウザ以外のアプリでは、OAuthにログインするためにWebブラウザーが必要なため、ここで少し難しくなります。電話またはデスクトップアプリからログインするには、ブラウザーを起動してFacebookにリダイレクトする必要があります。さらに悪いことに、ブラウザがFacebookアクセストークンを何らかのメカニズムを介してアプリケーションに渡す方法が必要です。

これでほとんどの質問に答えられることを願っています。もちろん、FacebookをTwitter、Google、またはその他のOAuthベースの認証サービスに置き換えることができます。

誰かがこれに対処する簡単な方法を持っているかどうかを知りたいと思います。

311
Miguel

@Miguelの各ケースの完全なフローの説明に非常に感謝していますが、Facebook Authenticationの部分にいくつか追加したいと思います。

Facebookは Javascript SDK を提供します。これを使用してクライアントエンドで直接アクセストークンを取得し、サーバーに渡して、Facebookからすべてのユーザー情報をさらに取得するために使用できます。したがって、基本的にリダイレクトは必要ありません。

さらに、モバイルアプリケーションにも同じAPIエンドポイントを使用できます。 FacebookのAndroid/iOS SDKを使用し、クライアント側でFacebookのaccess_tokenを取得してサーバーに渡します。

説明したステートレスの性質に関して、get_access_tokenを使用してトークンを生成し、クライアントに渡すと、このトークンもサーバーに保存されます。それで、セッショントークンと同じくらい良いです、そして、これがそれをステートフルにすると思いますか?

ちょうど私の2セント。

11
Madhur

以下は、認証に役立つ素晴らしい記事です。

  • フェイスブック
  • ツイッター
  • グーグル
  • ローカル認証

Easy Node Authentication:Setup and Local

3
myusuf