13

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

まったく同じ Web サービスを使用して Windows アプリケーションを作成したいと考えています。認証を処理するために、認証サービスを有効にし、 「ログイン」を呼び出してユーザーを認証できます...オーケー、大丈夫です...しかし、他のサービスクライアントでその認証Cookieを設定するにはどうすればよいですか?!

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

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

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

クライアント アプリケーション サービスは別の代替手段ですが、すべての例は、ユーザー、ロール、およびプロファイルを取得する方法を示すことに限定されています...しかし、クライアント アプリケーション サービスを使用して認証されると、その認証 Cookie を取得する方法があるはずです。同じサーバーにコールバックするときにサービスクライアントに接続されました。

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

4

6 に答える 6

5

私はついにこれを機能させる方法を見つけました。認証には、「WCF Authentication Service」を使用しています。サービスの認証時に、認証 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 スタックを使用することをお勧めします。

于 2008-09-11T21:59:47.800 に答える
2

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

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

たまたま、メンバーシッププロバイダーを使用してサービスへのすべての呼び出しを認証する場合、WCFが適切に機能することがわかりました。したがって、与えられた例では、メンバーシッププロバイダー認証ガビンをMyDataServiceのサービス構成に追加し、個別の認証サービスをまったく持たないようにする必要があります。

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

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

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

これが提供しないことの1つは、「ログイン」機能を提供する機能です。そのためには、何もしない(認証された!)サービス契約を提供するか(認証が失敗した場合に障害を発生させる以外)、元の参照記事で説明されているようにメンバーシッププロバイダーサービスを使用できます。

于 2008-09-11T20:21:41.233 に答える
1

クライアントで、サービスの <binding> タグ (<system.serviceModel> 内) を次のように変更します。

アプリは Cookie を永続化して使用する必要があります。ログイン後に IsLoggedIn が true を返すようになったことに注意してください。Cookie を許可していない場合は false を返します。

于 2009-07-09T04:15:16.783 に答える
0

System.NetのCookieContainerオブジェクトを確認する必要があります。このオブジェクトを使用すると、ブラウザ以外のクライアントがCookieを使用できなくなります。これは、私たちが最後にその問題に遭遇したときに私のチームが使用したものです。

これは、それを使用する方法についての簡単な記事です。そこにもっと良いものがあるかもしれませんが、これはあなたが始めるはずです。

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

于 2009-01-16T18:45:23.210 に答える
0

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

于 2009-05-11T20:43:18.353 に答える
0

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

私は後で何かを嘲笑してあなたに送ろうとします。

--larsw

于 2008-09-15T09:51:03.493 に答える