6

SPA (Single Page Application - BackboneJS で開発) があり、そのデータ用にステートレスな RESTful バックエンド API が必要な場合。サード パーティのシングル サインオンがユーザーにとって物事を非常に簡単にする方法が気に入っています。

しかし、このようなステートレス環境では、すべてのリクエストで認証が行われることを理解していますか? その場合、サードパーティの SSO を使用している場合。GitHub、毎回ユーザーを認証するために GitHub にアクセスする必要はありませんか? そのような状況のベストプラクティスは何ですか? 非常に一般的なユースケースだと思いますか?- ユーザーが Google/GitHub などを介してログインできるようにし、ステートレス REST API からデータを取得できるようにします

4

3 に答える 3

11

免責事項:)

私の製品にそのようなことを実装し、多くの懸念事項と技術 (特に 100% ステートレス REST バックエンドを使用したバックボーンを使用した SPA) を共有しました。 「答え」になるのではなく、議論の結果から学ぶための会話のきっかけになります。私もこのトピックについて学ぶべきことがかなりあると思います。


まず、100% ステートレスになるべきだと思います。そして 100% とは、100% を意味します :) API レイヤーだけでなく、アプリケーション全体 (もちろんクライアントを除く) もステートレスである必要があります。セッションを別のレイヤー (redis など) に移動すると、問題が少し移動するだけで、解決にはなりません。すべて (特にスケーリング) が非常に簡単になり、後でこの決定に感謝することになります。

したがって、はい、すべてのリクエストで認証が必要です。ただし、これは毎回認証プロバイダーにアクセスする必要があるという意味ではありません。私が学んだことの 1 つは、ユーザーが FB/GitHub/Whatever (今後はリモート サービス) を介して認証できるようにすることは、サインアップ/サインインの苦痛を軽減する手段にすぎないということです。ユーザーの個人データベースをさらに拡大する必要があります。もちろん、各ユーザーは「リモート」ユーザーに関連付けられますが、認証が実行されるとすぐに、アプリは「リモート」ユーザー (例: GitHub ユーザー) ではなく、「あなたの」ユーザーを参照する必要があります。

実装

これが私が実装したものです:

  1. API メソッドには常に認証トークンが必要です。認証トークンはシステムのユーザーを表すハッシュであるため、 を呼び出すとPOST /api/board?name=[a_name]&auth=[my_token]、誰が呼び出しているかがわかり、権限を確認して、新しく作成されたエンティティboardを正しいユーザーに関連付けることができます。

  2. 上記のトークンは、リモート サービスのトークンとは関係ありません。それらが計算されるロジックは、私のアプリに固有のものです。ただし、リモートユーザーにもマップされている私のユーザーをマップするため、必要な場合に情報が失われることはありません。

  3. リモートサービスを介してユーザーを認証する方法は次のとおりです。サービス ドキュメントで指定されているように、リモート認証を実装します。通常、これは OAuth または OAuth に似ています。これは、最終authToken的にリモート ユーザーを表す を取得することを意味します。このトークンには 2 つの目的があります。

    • これを使用して、ユーザーとして機能するリモート サービスで API メソッドを呼び出すことができます
    • 少なくともリモート サービスによって、ユーザーが本人であることを保証します。
  4. ユーザーがリモート サービスで自身を認証するとすぐに、一致するユーザーをシステムにロードまたは作成します。を持つユーザーがremote_id: GitHub_abc123システムに存在しない場合は作成し、そうでない場合はロードします。このユーザーが持っているとしましょうid: MyApp_def456authTokenユーザーを表す独自のロジックを使用しても作成MyApp_def456し、それをクライアントに渡します (Cookie は問題ありません!!)。

  5. ポイント1に戻ります:)


ノート

認証はすべてのリクエストで実行されます。これは、ハッシュと暗号化関数を処理することを意味し、定義により低速です。ここで、bcrypt20 回の反復で使用すると、アプリが強制終了されます。ユーザーがログインするときにパスワードを保存するために使用しますが、その後はあまり重くないアルゴリズムをauthToken使用します (個人的には、SHA-256)。このトークンは寿命が短く (クラックする平均時間よりも短いとしましょう)、サーバー マシンでの計算は非常に簡単です。ここには正確な答えはありません。さまざまなアプローチを試し、測定し、決定します。代わりに、私が確信しているのは、セッションの問題よりもこの種の問題が発生することを好むということです。より多くのハッシュを計算する必要がある場合、またはより高速に計算する必要がある場合は、CPU パワーを追加します。セッションとクラスター化された環境では、メモリの問題、負荷分散とスティッキー セッションの問題、またはその他の可動部分 (redis) があります。

は常にパラメーターとして渡されるため、HTTPS絶対に必須です。authToken

于 2013-08-20T15:18:03.003 に答える
1

私がそれを実装する方法は、クライアント (バックボーン) と RESTful Web サーバーの間にプロキシを導入することです。プロキシは、SSO と連携してユーザーの認証を管理します。したがって、API および/またはクライアント/Web サーバーを変更する必要はありません。ここに簡単なデモがあります:

var http = require('http'),
    httpProxy = require('http-proxy'),
    express = require('express');

var proxy = new httpProxy.RoutingProxy();
var app = express();

function ensureAuthenticated(req, res, next) {
  if (isLoggedIn) { return next(); }
  res.redirect('/');
}

// This should be your (RESTful) webserver
http.createServer(function (req, res) {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
  res.end();
}).listen(9000);

var isLoggedIn = false;

app.get('/', function(req, res){
  console.log(isLoggedIn)
  res.send('Logged in? ' + isLoggedIn);
});

app.get('/login', function(req, res){
  isLoggedIn = true;
  res.redirect('/');
});

app.get('/logout', function(req, res){
  isLoggedIn = false;
  res.redirect('/');
});

app.all('/api/*', ensureAuthenticated, function(req, res) {
  return proxy.proxyRequest(req, res, {
    host: 'localhost',
    port: 9000
  });
});

app.listen(8000);

このページに初めてアクセスすると、ログアウトされ、 へのすべての呼び出し/api/somethingが にリダイレクトされ/ます。ログに記録される (ページにアクセスする/login) と、すべての要求/api/*がプロキシ経由で、ポート 9000 でリッスンしている Web サーバーにルーティングされます。

特に、app.all('/*', ...)API サーバーへのすべての呼び出しを設定すると、同じままですが、認証レイヤーが追加されます。この概念は、oauth で拡張するのは簡単です (ノードを使用している場合は、 passportjsを参照してください)。

于 2013-08-16T10:43:01.800 に答える
0

Facebook の JavaScript SDK で使用されているアプローチを採用できます。

このドキュメント ページでは、Facebook for web でログインするためのクイック スタートを提供します。それほど深くはありませんが、彼らのアプローチの基本的な使い方を説明しています。ただし、署名の可能性については言及していません。

アプリに Facebook ログオンを登録すると、Facebook のアプリケーション ダッシュボードからアプリ シークレットが取得されます。

ユーザーが Facebook 経由でアプリにログオンすると、JavaScript は認証オブジェクトを取得します。このオブジェクトには署名が含まれています。(ダッシュボードで正しく設定した場合。)

RESTful サーバーへのクライアント呼び出しでこの認証オブジェクトを提供し、サーバーで署名が正しいことを確認できます。このようにして、ユーザーが facebook によって認証されたこと、このユーザーであり、アプリケーションに対して認証されたことがわかります。

このドキュメント ページでは、署名付き認証の使用方法について説明します。見出しの「ゲーム」に怯える必要はありません。どの Web アプリでも問題なく動作します。

Facebook のみに SSO を許可する代わりに、他の OAUTH プロバイダーを使用して、FB ログインと同じ精神で何かを実装できます。

danielepolencic によって提案されたソリューションを使用しますが、同じ node.js インスタンス内のプロキシの代わりにログイン用の別のサーバーを持つように変更してください。このサービスは、プロバイダーとの OAUTH チェックを行い、クライアントとのセッションを維持します。短い存続時間で、署名されたトークンをクライアントに発行します。クライアントは、有効期限が切れる前に新しいトークンを要求する必要があります。

次に、アプリケーションで使用されるログイン用の Facebook JavaScript SDK と同様の機能を備えたクライアント側 JavaScript を実装します。この関数は、新しいトークンをポーリングするか、要求に応じて新しいトークンを取得することができますが、シナリオにとって最も効率的です。

クライアントはリクエストごとにこのトークンを RESTful API に提供し、サーバーは署名をチェックします。Facebook SSO と同様です。

セッションはまだありますが、visavis はまったく別のマシンで維持できます。このサービスは、RESTful API を使用してサーバーとは独立してスケーリングできます。

ただし、このアプローチは中間者攻撃やリプレイ攻撃の影響を受けやすいことに注意してください。https なしで使用するのはおそらく賢明ではありません。

于 2013-08-19T17:30:14.633 に答える