4

複数の WCF サービスをホストする既存の asp.net Web サイトで CORS を有効にしようとしています。残念ながら、私はそれを機能させるのに苦労しています。一見したところ、(存在しない) ログイン ページにリダイレクトされているので、カスタム認証サービスによって生成されている認証 Cookie に問題がある可能性があります。

先に進む前に、現在のシナリオの簡単な説明を次に示します。

  • いくつかの Web サービス (認証サービス以外はすべて、認証されたユーザーのみがアクセスできます) を公開するサイト A と、Web サービスと対話しようとするページを持つサイト B があります。
  • このシナリオを再現するために、サービスと HTML ページを同じ場所に配置し、cors 呼び出しをシミュレートするためにエイリアス (hosts ファイル) を作成しました (outro.pt と呼んでいるとしましょう)。 )
  • FormsAuthentication.GetAuthCookie を使用して認証 Cookie が生成され、Response.AppendCookie メソッドを呼び出して応答に追加されます。
  • 認証は期待どおりに機能します。最初に OPTIONS 呼び出しがあり、その後に POST 呼び出しが続きます。2 番目の Web サービスが呼び出されると (再度 POST)、プリフライト チェックは行われません (最初の呼び出しでは、プリフライト チェックを 5 分間キャッシュするために Access-Control-Max-Age ヘッダーが生成されるため)、Web サイト (outro .pt) は最終的に 302 を返し、ブラウザをログイン ページにリダイレクトします。

    先に進む前に、プリフライトを処理し、cors 呼び出しを許可するために使用されるデモ コードを次に示します (アプリの beginrequest イベント内に配置しました)。

    private void Application_BeginRequest(object sender, EventArgs e) {
        var ctx = HttpContext.Current;
    
        //allow credentials: always
        ctx.Response.AddHeader("Access-Control-Allow-Credentials", "true");
    
        //add allow origin header
        if (ctx.Request.Headers["Origin"] != null) {
            ctx.Response.AddHeader("Access-Control-Allow-Origin", ctx.Request.Headers["Origin"]);
        }
    
        if (ctx.Request.Headers["Access-Control-Request-Headers"] != null) {
            ctx.Response.AddHeader("Access-Control-Allow-Headers", ctx.Request.Headers["Access-Control-Request-Headers"]);
        }
    
        if (ctx.Request.HttpMethod.ToUpper() == "OPTIONS" ) {
            ctx.Response.AddHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");
            //keep preflight info for 5 mins
            ctx.Response.AddHeader("Access-Control-Max-Age", (5 * 60).ToString());
            ctx.Response.End();
            return;
        }
    }
    

次に、認証 Cookie を生成するためのデモ コードを示します (これはデモ コードであるため、単純な汎用ハンドラーを使用することにしました。

    public void ProcessRequest(HttpContext context) {
        context.Response.ContentType = "application/json";
        var name = "";
        using (var reader = new StreamReader(context.Request.InputStream)) {
            var std = (Student)JsonConvert.DeserializeObject(reader.ReadToEnd(),typeof(Student));
            name = std == null ? "" : std.name;
        }
        if (!String.IsNullOrEmpty(name)) {
            var cookie = FormsAuthentication.GetAuthCookie(name, false);              
            cookie.Domain = "outro.pt";
            context.Response.AppendCookie(cookie);
            context.Response.Write(JsonConvert.SerializeObject(new {valid = true}));
        }
        else {
            context.Response.Write(JsonConvert.SerializeObject(new { valid = false }));    
        }

    }

ここで、フィドラーを使用した後、検証ハンドラーが呼び出されたときに Cookie が返されることがわかります。たとえば、前の認証ハンドラーへの呼び出しによって作成された 1 つの Cookie の例を次に示します。

Set-Cookie: .ASPXAUTH=1CB7EF39DBA39BDA2FD2AA0A0AAFDAB67821A286D04F1678C89CFD6036094A3F9C36D2C9E48FFE35B95C8A742F553138A8899E2CE63259F6DDC7A4D59868AF8A3F50EC037F1DAB73827B5D906A115C28FC8E4B744D661AF77592955F525E236D; ドメイン=outro.pt; パス=/; HttpOnly

一見すると、この認証 Cookie に問題はありません (正しいドメインに関連付けられており、outro.pt 内に保持されているページにアクセスするたびに送信されるはずですよね? - たとえ別のドメイン内に配置されていても)たとえば、outro.pt/demo/webservice.ashx? のような asp.net アプリ)

2 番目の Web サービスにアクセスしようとすると、ログイン ページにリダイレクトされたので、問題は認証 Cookie が送信されていないことだと思いました。フィドラーによると、この 2 番目の呼び出しの要求ヘッダーには Cookie が送信されません。いろいろやってみましたが、どうにもうまくいきません。

ドキュメントを読んだ後、cookie を送信するために必要なのは withCredentials フィールドを true に設定することだけだと思いますよね? ところで、jquery2 を使用して実行される 2 番目の Web サービス呼び出しは次のとおりです。

    var complete = url + "studentservice.ashx";
    payload = {
                    url: complete,
                    type: 'POST',
                    xhrFields: {
                        withCredentials: true
                    },
                    contentType: 'application/json',
                    crossDomain: true,
                    dataType: 'json'
                };
    $.ajax(payload)
                    .done(function (data, status, xhr) {
                        alert("success");

                    })
                    .fail(function (xhr, status, error) {
                        alert("error" + error);
                    });

では、アクセスする必要のある Web サービスに asp.net 認証が必要な場合に、cors を使用できた人はいますか? 私は何が欠けていますか?

ありがとう。

4

1 に答える 1

1

私は問題を発見したと思います: ユーザーを検証する (および Cookie を生成する) ための $.ajax メソッド呼び出しは withCredentials フィールドではなかったため、サーバーから返された Cookie は最終的に破棄されました。

于 2013-08-29T21:27:19.417 に答える