複数の 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 を使用できた人はいますか? 私は何が欠けていますか?
ありがとう。