2017-07-16 11 views
1

IdentityServer4での暗黙のフロー私はこれを達成するために、ユーザーがユーザーのパスワードを入力せずにログインし直す必要がないようにする必要があります。IdentityServer SSO - 私は、SSO(シングルサインオン)鉱山のアプリケーションからの利用者(ASPNETセッション状態を使用して、アイデンティティプロバイダ)に必要と使用するように構成された鉱山の別のアプリケーション(サービス・プロバイダー)にリダイレクト信頼できるアプリケーション

私はアイデンティティプロバイダのクライアントシークレットを使用して、アクセストークンをクエリパラメータとしてIdentityServer4認証エンドポイントにリダイレクトした後、カスタムバリデータまたは拡張機能許可を使用してアイデンティティを発行できると考えましたユーザーのパスワードも提供する必要なく、サービスプロバイダアプリケーションで使用するためのトークン。

私は、アイデンティティプロバイダへのアクセストークンを発行し、その後IdentityServer4にユーザーをリダイレクトするために管理してきましたが、IDトークンを発行することは私のために困難であることが判明しました。私はサンプルとドキュメンテーションを書きましたが、私は一言も言い表せません。

私はC#で、このシナリオに適切なアプローチと、おそらく包括的な例の方向を探しています。私は、アクセストークンとIDトークンを発行するためにハイブリッドフローを使用できることを理解するようになりました。私の最大の闘いは、ユーザーをリダイレクトする方法と、アクセストークンに基づいてユーザーにIDトークンを発行することです(これが許容できる方法であっても)。

簡単に言えば:私は(クライアントシークレット経由?)アイデンティティプロバイダとの信頼関係に基づいてアプリケーションBにIdentityServer4へのアプリケーションAからユーザーをリダイレクトしたいと思います。

注:私は、これは意見ベースの質問を検討したが、私はそこに1つのベストプラクティスであり、それは私が求めているものだと考えている私の研究に基づくものとすることができる理解しています。

答えて

1

にリダイレクトをトリガーするアプリケーションAがIdentityServerからの復帰時に読むことができるあなたにreturnurlにおけるいくつかのカスタムパラメータを含めることができます

  1. アプリケーションA(IDプロバイダ)でユーザーを認証
  2. トークンエンドポイントと共有秘密情報を使用してIdentity Server 4からアクセストークンを取得します。
  3. リダイレクト時にヘッダーが保持されないため、クエリトークンパラメータとしてアクセストークンを追加します。
  4. ユーザーを、usernameなどの識別情報を受け付けるアカウントコントローラメソッドにリダイレクトします。このメソッドは、アクセストークンパラメータのクエリ文字列をチェックするカスタムミドルウェアクラスによって保護されています。トークンが存在する場合、トークンは認証ヘッダーに追加されます。これは、このコントローラメソッドにヒットすることをユーザーに許可します。
  5. コントローラーメソッドは、ユーザーに署名し、エンドポイント/connect/authorize/loginにリダイレクトします。
  6. 最後に、ログインエンドポイントは、クッキーを設定し、URL redirect_uriクエリパラメータで指定されたアプリケーションB(サービスプロバイダ)、にユーザーをリダイレクトします。共有シークレットのため

構成:

クライアントに適切な許可タイプ、秘密と新しいスコープ名を追加します。新しいスコープは、ログ内のアクセストークンの問題のデバッグに役立ちます(特に、複数のアプリケーションがID4サーバーに当たる場合)。また、サービスプロバイダのURLをクライアントRedirectUrisに追加してください。そうしないと、「無効なリダイレクト」エラーが表示されます。

  AllowedGrantTypes = new List<string> { GrantType.Implicit, GrantType.ClientCredentials }, 
      ClientSecrets = new List<Secret> { 
       new Secret(_clientSecrets.ExternalIdpSecret.Sha256(), clientID) 
      }, 
      AllowedScopes = new List<string> 
      { 
       "newScopeName" 
      }, 
      RedirectUris = new List<string> 
      { 
       $"http://localhost:<portnumber>" 
      } 

次に、カスタムミドルウェアを追加します。

public class QueryStringOAuthBearerMiddleware 
{ 
    private readonly RequestDelegate next; 

    public QueryStringOAuthBearerMiddleware(RequestDelegate next) 
    { 
     this.next = next; 
    } 

    public async Task Invoke(HttpContext context) 
    { 
     this.BeginInvoke(context); 
     await this.next.Invoke(context); 
     this.EndInvoke(context); 
    } 

    private void BeginInvoke(HttpContext context) 
    { 
     if (context.Request.Query.ContainsKey("accesstokenparametername")) 
     { 
      var accessToken = context.Request.Query.First(p => p.Key == "accesstokenparametername"); 

      if (!string.IsNullOrEmpty(accessToken.Value)) 
      { 
       context.Request.Headers.Add("Authorization", "Bearer " + accessToken.Value); 
      } 
     } 
    } 

    private void EndInvoke(HttpContext context) 
    { 
    } 
} 

設定にミドルウェアを追加します。

 app.UseMiddleware<QueryStringOAuthBearerMiddleware>(); 

ログイン方法を作成します。クライアントアプリケーションのための

[HttpGet] 
    [Authorize] 
    public async Task<IActionResult> Login2(string userName, string returnURL) 
    { 
     await _httpContextWrapper.SignInAsync(userName); 

     return Redirect(returnURL); 
    } 

構成(IDP):

次のようになりますあなたのクライアント側のコード:

var disco = await DiscoveryClient.GetAsync("http://localhost:<portnumber>"); 
var tokenClient = new TokenClient(disco.TokenEndpoint, "clientIdentifier", "IUsedAGuidHere"); 
var tokenResponse = await tokenClient.RequestClientCredentialsAsync("newScopeName"); 

var redirectURL = string.Format("http://localhost:2228/account/Login2?userName=<UserIDValue>&returnURL={1}&accesstokenparametername={0}", 
      tokenResponse.AccessToken, 
      Server.UrlEncode(
       string.Format("/connect/authorize/login?client_id={3}&redirect_uri={2}&response_type=id_token%20token&scope=<ImplicitFlowScopes>&state={0}&nonce={1}", 
       CryptoRandom.CreateUniqueId(), 
       CryptoRandom.CreateUniqueId(), 
       Server.UrlEncode("http://localhost:<PortNumber>"), 
       "ClientIdentifier"))); 

Response.Redirect(redirectURL, false); 

注:これを取ることができなくなりますのでご了承下さいAS-ISをコード化して動作させる。私はリソースのセキュリティを保護するために大きく変更しました。

+0

アプリケーションAとBは* ClientSecrets *で同じ* Secret *を共有していますか? @alan – Babak

+0

@BabakアプリケーションBは、その懸念がOAuthトークンであるため、ClientSecretを活用しません。簡単に言えば、アプリケーションAはClientSecretを使用してOAuthトークンを取得し、そのトークンをアプリケーションBに提示します。 – alan

+0

しかし、認証アプリケーションはトークンを受け入れず、Login2()に入ります。どんな意見ですか? – Babak

0

私は

アプリケーションA ...私は前方の次のアプリへ、その後、最初のアプリケーションAと認証の世話をするかもしれないと思う - > IdentityServer - >アプリケーションA - >アプリケーションB.

あなたは、私は、以下の流れによって、この作業を取得するために管理アプリケーションB.

+0

私はこの試みに感謝しますが、基本的には私の質問の「単純に置いた」セクションを修正しました。私は自分で解決策を見つけることができました。 – alan

関連する問題