WCF、ASP.NET メンバーシップ プロバイダーおよび認証サービス

StackOverflow https://stackoverflow.com/questions/56112

  •  09-06-2019
  •  | 
  •  

質問

WCF サービス (BasicHttpBinding) と通信する Silverlight 2 アプリケーションを作成しました。Silverlight コンテンツをホストしているサイトは、ASP.NET メンバーシップ プロバイダーを使用して保護されています。WCF サービスから HttpContext.Current.User.Identity.Name を使用して現在のユーザーにアクセスでき、AspNetCompatibilityRequirementsMode をオンにしています。

次に、まったく同じ Web サービスを使用して Windows アプリケーションを作成したいと考えています。認証を処理するために、 認証サービス, 、「login」を呼び出してユーザーを認証できます...わかりました、大丈夫です...しかし、他のサービス クライアントに設定された認証 Cookie を一体どうやって取得するのでしょうか?!

両方のサービスは同じドメインでホストされています

  • MyDataService.svc <- 私のデータを扱うもの
  • AuthenticationService.svc <- Windows アプリが認証のために呼び出す必要があるもの。

Windows クライアント用に新しいサービスを作成したり、別のバインディングを使用したりしたくありません...

クライアント アプリケーション サービスも別の代替手段ですが、すべての例は、ユーザー、ロール、プロファイルを取得する方法を示すことに限定されています。ただし、クライアント アプリケーション サービスを使用して認証されると、同じサーバーにコールバックするときに、サービス クライアントに添付された認証 Cookie を取得する方法が必要になります。

同僚からの入力によると、解決策は wsHttpBinding エンドポイントを追加することですが、それを回避できることを願っています...

役に立ちましたか?

解決

ついにこれを機能させる方法を見つけました。認証には「」を使用しています。WCF 認証サービス」。認証時に、サービスは認証 Cookie の設定を試みます。この Cookie を応答から取得し、同じマシン上の他の Web サービスに対して行われた他のリクエストに追加する必要があります。これを行うコードは次のようになります。

var authService = new AuthService.AuthenticationServiceClient();
var diveService = new DiveLogService.DiveLogServiceClient();

string cookieHeader = "";
using (OperationContextScope scope = new OperationContextScope(authService.InnerChannel))
{
    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
    bool isGood = authService.Login("jonas", "jonas", string.Empty, true);
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name];
    cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie];                
}

using (OperationContextScope scope = new OperationContextScope(diveService.InnerChannel))
{
    HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
    httpRequest.Headers.Add(HttpRequestHeader.Cookie, cookieHeader);
    var res = diveService.GetDives();
}      

ご覧のとおり、2 つのサービス クライアントがあり、1 つは認証サービス用で、もう 1 つは実際に使用するサービス用です。最初のブロックは Login メソッドを呼び出し、応答から認証 Cookie を取得します。2 番目のブロックは、「GetDives」サービス メソッドを呼び出す前に、リクエストにヘッダーを追加します。

私はこのコードにはまったく満足していません。より良い代替案は、「サービス参照」の代わりに「Web 参照」を使用し、代わりに .NET 2.0 スタックを使用することだと思います。

他のヒント

WCF によって作成された Web サービスなどの Web サービスは、多くの場合、「ステートレス」な方法で使用するのが最適であるため、Web サービスへの各呼び出しは新たに開始されます。これにより、クライアントの状態を呼び出す「セッション」が必要なくなるため、サーバー コードが簡素化されます。また、サーバーの状態について何かを想定するチケット、Cookie、その他の厄介な要素を保持する必要がないため、クライアント コードも簡素化されます。

ここで説明されている方法で 2 つのサービスを作成すると、ステートフル性が導入されます。クライアントは「認証済み」か「未認証」のいずれかであり、MyDataService.svc はどちらかを判断する必要があります。

偶然ですが、メンバーシップ プロバイダーを認証に使用すると WCF がうまく機能することがわかりました。 サービスに電話します。したがって、上記の例では、メンバーシップ プロバイダーの認証ガビンを MyDataService のサービス構成に追加し、別個の認証サービスをまったく持たないようにする必要があります。

詳細については、MSDN の記事を参照してください。 ここ.

[怠け者の私にとってこれが非常に魅力的なのは、これが完全に宣言的であるということです。アプリケーションの app.config に MembershipProvider の適切な構成エントリを分散するだけです。ビンゴ!サービス内のすべてのコントラクトへのすべての呼び出しが認証されます。]

これが特別に高速になるわけではないことに注意するのは当然です。認証データベースに SQL Server を使用している場合は、サービス呼び出しごとに少なくとも 1 つ、おそらく 2 つのストアド プロシージャ呼び出しが必要になります。多くの場合 (特に HTTP バインディングの場合)、サービス呼び出し自体のオーバーヘッドが大きくなります。そうでない場合は、認証リクエストをキャッシュするメンバーシップ プロバイダーを独自に実装することを検討してください。

これが一つ しません give は、「ログイン」機能を提供する機能です。そのためには、(認証が失敗した場合にエラーが発生する以外は) 何も行わない (認証済みの) サービス コントラクトを提供するか、元の参照記事で説明されているメンバーシップ プロバイダー サービスを使用することができます。

クライアントで、サービスの <binding> タグ (<system.serviceModel> 内) を変更して以下を含めます。allowCookies="true"

これで、アプリは Cookie を永続化して使用できるようになります。ログイン後に IsLoggedIn が true を返すようになりました。Cookie を許可していない場合は false を返します。

カスタム メッセージ インスペクターと動作の背後に余分なコードの多くを隠すことができるため、OperationContextScope を自分でいじる必要はありません。

後で何かモックして送ってみます。

--larsw

を見てみる必要があります。 クッキーコンテナ System.Net のオブジェクト。このオブジェクトにより、ブラウザ以外のクライアントが Cookie を保持できるようになります。これは、私のチームが最後にその問題に遭遇したときに使用したものです。

簡単な記事はこちら それをどのように使用するかについて。他にもっと良いものがあるかもしれませんが、まずはこれで始めてください。

現在の WCF サービスと Silverlight 2 アプリケーションのセットではステートレス ルートを採用しました。Silverlight 2 を TransportWithMessageCredential セキュリティでバインドされたサービスで動作させることは可能ですが、Silverlight 側でカスタム セキュリティ コードが必要になります。その結果、メッセージ ヘッダーにユーザー名とパスワードを設定するだけで、どのアプリケーションでもサービスにアクセスできるようになります。これはカスタム IRequestChannel 実装で 1 回実行できるため、開発者は自分で値を設定することを心配する必要がありません。ただし、WCF には開発者がこれを行う簡単な方法があり、それは serviceProxy.Security.Username と serviceProxy.Security.Password、または同様に単純なものであると思います。

これは、しばらく前に、Web サービスに対する認証に Client Application Services を使用していたときに書きました。メッセージ インスペクターを使用して Cookie ヘッダーを挿入します。ドキュメントとデモ プロジェクトを含む Word ファイルがあります。あなたがやっていることと全く同じではありませんが、かなり近いものです。からダウンロードできます ここ.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top