web-dev-qa-db-ja.com

サードパーティのサービスによる承認後、OAuth 2.0を使用してセッションを永続化するにはどうすればよいですか?

開発中のアプリケーションにOAuth 2ベースの認証モデルを実装しています。エンドユーザーにFacebookでログインする機能、またはでメール/パスワードアカウントを設定する機能を提供しています。私のAPI。メール/パスワード認証はパスワード付与を使用して簡単です。Facebookのログインフローに関するヘルプを探しています。

私のアプリケーションは、JSON API(私の「リソースサーバー」)を使用するシングルページアプリケーションです。 Facebook JavaScript SDKを使用して、Webアプリがエンドユーザーの電子メールアドレスにアクセスすることを承認しています。

ユーザーがFacebookでログインしようとすると、プロセス全体がFacebookとWebアプリケーションの間で行われます。その結果、私のAPIは、FacebookのOAuthサーバーでトークンを検証するまで、Facebook認証トークンを信頼できません。

今のところ、Facebook accessTokenをAPIに渡しています。APIは、「me」グラフAPIのサーバー間呼び出しを介して、Facebookでのユーザーの承認を確認します。これが私の現在の設定の図です:

My current OAuth flow

したがって、この時点で、Facebookアクセストークンと電子メールアドレスを持っています。 APIサーバーとWebアプリケーションの間でセッションを永続化する必要があります。この時点でセッションを永続化する標準的な方法は何ですか?

OAuthのドキュメントを読むと、これは私のAPIサーバーとWebアプリケーションの間で「暗黙の許可」を必要とするタイプの状況のようですが、その許可タイプは 私が使用しているOAuthパッケージ 。パッケージの作成者も 暗黙の付与は「非常に安全ではない」と言っています

私の他の考えは、ランダムなクライアントIDとクライアントシークレットを作成し、それらをWebアプリに返して、資格情報の付与を介してアクセストークンを要求できるようにすることです。これは私には非論理的に思えます。アクセストークンを作成してクライアントに送り返して直接使用しないのはなぜですか?

Facebookからの最初の承認後、WebアプリとAPIサーバー間で直接認証を維持する必要がありますが、それは正しいですか?

ランダムなパスワードを生成してユーザーにHTTPBasicトークンを送信するだけでよいことに気付きましたが、メリットがない限り、OAuthを使用したいと思います。

13
Ben Harold

DynamicApis.comであなたが話していることを正確に実行しています。

これが私たちがしていることです:

1)ユーザーにログインを促します。この場合、oAuth2アクセストークンを自分で作成しますOR Facebook、githubなどにプロキシできます...しかし、結局のところ、 DynamicApisのセッションを駆動するoAuth2トークンは私たちが所有していますが、GitHubなどのサードパーティによって完全に作成された場合、残りのワークフローはまったく同じになります。

2)ユーザーは電子メール/パスワードでログインします。

3)ユーザーは認証コードを使用してDynamicApis.comにリダイレクトされます

4)DynamicApis.comは、アクセストークン(サーバー間呼び出し)の認証コードを交換します。 この時点で、oAuth2フローについて説明しました

5)この時点で、(たとえば暗号化)そのユーザーに代わって返され、発行されたアクセストークンを、セッションプロバイダー(SQL Serverベースとしましょう)。このセッションプロバイダーはDynamicApis.comが所有しています。

6)これで、セッションプロバイダーは通常どおりに機能します。ログインしたユーザーを表すキー(ハッシュ/暗号化されたアクセストークン)と、そのキーに関連付けられた複数のキー/値があります。

  • セッションプロバイダーは、ユーザーに代わってデータベースまたは使用するものに保存するデータのセッション状態(キーと値のペア)を保持します

  • セッションプロバイダーの有効期限は、アクセストークンの有効期限と同じ(またはアクセストークンよりも短い)必要があります。

  • ユーザーがログアウトすると、セッションは破棄されます。

  • セッションキーは、Cookie、URLに暗号化された形式で存在するか、ページに非表示になっている必要があります(セッションキーが今日保持されているのと同じように)

7)プーフ。ログインしたユーザーのセッションがあります。

必要に応じて、組み込みのASP.NETセッションプロバイダーロジックの多くを実際に再利用できます。または、DynamicApis.comにあるように、独自の自家製システムを構築することもできます。

2
Jerrod Horton

可能であれば、oauth実装で、独自のカスタム付与クラスと認証プロバイダーをコーディングできます。

この種の認証用に新しいクライアントIDを定義します。

  1. ユーザーはFacebookを使用して認証します。

  2. Facebookはクライアントのトークンを生成します。

  3. クライアントは、このアクセストークン、メールアドレス、認証タイプ/クライアントIDを使用してバックエンドアプリケーションにリクエストを送信します(「facebook」としましょう)

  4. カスタム付与によって、使用するトークンの種類が決まります。クライアントID /認証タイプ(上記)を制御できます。
  5. 認証タイプが「facebook」の場合、セッションストアへのアクセストークンがここにない場合はFacebook apiに要求し、問題がない場合はセッションストア(データベース、redisなど)に保存します。毎回fbを聞かないようにセッションストアに入れました(とても基本的なコンセプトです)
  6. 次に、oauthは構成とともにトークンを返します。
  7. クライアントは、クライアントID /認証タイプで次のリクエストのトークンを送信します。資格情報はFacebookトークンになり、メールはユーザー名になります。

カスタム付与がトークンタイプを決定します(Springsecurity-oauth実装)

    String clientId = tokenRequest.getClientId();
    ClientDetails client = clientDetailsService.loadClientByClientId(clientId);
    Map<String, String> parameters = tokenRequest.getRequestParameters();
    String username = parameters.get("username"); //username is email
    String password = parameters.get("password"); //password is fb access token
    Authentication authentication = null;
    if ("facebook".equals(clientId)) {
        authentication = new FacebookAuthenticationToken(username, password);
    } else {
        authentication = new UserAuthenticationToken(username, password);
    }
    authentication = authenticationManager.authenticate(authentication);

認証プロバイダーはFacebookトークンをチェックして検証します。

public class FacebookAuthenticationProvider implements AuthenticationProvider {

@Autowired
private FacebookApi facebookApi;

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    String username = authentication.getName();
    String password = (String) authentication.getCredentials();
    // you can check your facebook session store
    boolean valid = facebookApi.isValidToken(username, password);

    if (!valid) {
        throw new BadCredentialsException("Username not found.");
    }

    Collection<? extends GrantedAuthority> authorities = user.getAuthorities();

    return new FacebookAuthenticationToken(user, password, authorities);
}

@Override
public boolean supports(Class<?> authentication) {
    return FacebookAuthenticationToken.class.isAssignableFrom(authentication);
}
}

サンプルとしてコードを入れました。

私は通常、最初のFacebookログイン(メールの取得)後に、ユーザーに内部アプリのパスワードを設定するように強制します。その後、すべてがはるかに簡単になります。あなたは私が何を意味するのか理解することができます。

2
user3754542