4

そのため、ロギング フレームワークをテストする目的で、企業の Web サイトで同時に複数のログインをシミュレートして例外を生成しようとしています (スレッド同期に問題がある可能性があると考えられます)。とにかく、プログラムでウェブサイトにログインする必要があります。これが私がこれまでに持っているものです:

        // Block 1
        Uri url = new Uri("http://withheld");
        HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
        request.Method = "GET";
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        string viewState = string.Empty;
        string previousPage = string.Empty;
        string eventValidation = string.Empty;
        using (StreamReader reader = new StreamReader(response.GetResponseStream()))
        {
            string strResponse = reader.ReadToEnd();
            viewState = HttpUtility.UrlEncode(GetTagValue(strResponse, "__VIEWSTATE"));
            previousPage = HttpUtility.UrlEncode(GetTagValue(strResponse, "__PREVIOUSPAGE"));
            eventValidation = HttpUtility.UrlEncode(GetTagValue(strResponse, "__EVENTVALIDATION"));
        }


        // Block 2
        string username = "user01";
        string password = "password99";
        HttpWebRequest request2 = WebRequest.Create(url) as HttpWebRequest;
        request2.KeepAlive = true;
        request2.Method = "POST";
        request2.ContentType = "application/x-www-form-urlencoded";
        string postData = string.Format("__LASTFOCUS=&ctrlCreateNewPassword_scriptManagerMaster_HiddenField=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE={0}&__PREVIOUSPAGE={1}&__EVENTVALIDATION={2}&UserName={3}&Password={4}&LoginButton=Log+in", new string[] { viewState, previousPage, eventValidation, username, password});
        byte[] dataBytes = UTF8Encoding.UTF8.GetBytes(postData);
        request2.ContentLength = dataBytes.Length;
        using (Stream postStream = request2.GetRequestStream())
        {
            // Here's the problem
            postStream.Write(dataBytes, 0, dataBytes.Length);
        }
        HttpWebResponse httpResponse = request2.GetResponse() as HttpWebResponse;
        // At this point httpResponse.Cookies is null
        // I believe it's because the line above has actually initiated another
        // request/response which DOES NOT include the authentication cookie.
        // See fiddler output below to understand why I think that.


        // Block 3
        //Uri url2 = new Uri("http://Withheld/GenerateException.aspx");
        //http = WebRequest.Create(url2) as HttpWebRequest;
        //http.CookieContainer = new CookieContainer();
        //http.CookieContainer.Add(httpResponse.Cookies);
        //HttpWebResponse httpResponse2 = http.GetResponse() as HttpWebResponse;

かなり簡単に見えますよね?うまくいきません。viewState などが必要かどうかはわかりませんが、通常のブラウザーの機能を可能な限り真似したいと考えました。

何が起こっているかを知ることができるのは、これです:

  1. 単純な GET でページにアクセスします。これにより、次のリクエストに含まれるように解析されたビューステートなどが得られます。
  2. postStream.Write() を使用して、viewstate、ユーザー名、パスワードなどをサーバーに投稿します。この時点で、サーバーは認証 Cookie で応答し、/Default.aspx に転送します。
  3. ここで reqest2.GetResponse() を実行しますが、/default.aspx に転送して認証 Cookie を取得する応答を取得する代わりに、この行が実際に /default.aspx のリソースを取得する別の要求を引き起こしているようです。問題は、httpWebResponse には次のリクエストに必要な認証 Cookie が含まれていないことです (現在はコメントアウトされています)。

なんで?なぜこの邸宅でこれが振る舞うのか、どうすれば適切に処理できますか. 何が起こっているのかをさらに説明するために、フィドラーからの出力を次に示します。

ブロック 1 は、この要求/応答要求ヘッダーを生成します。

GET http://withheld/Login.aspx HTTP/1.1
Host: withheld
Connection: Keep-Alive

応答ヘッダー:

HTTP/1.1 200 OK
Connection: close
Date: Mon, 04 Feb 2013 16:37:37 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Set-Cookie: .EXTASPXAUTH=; expires=Tue, 12-Oct-1999 04:00:00 GMT; path=/; HttpOnly
Cache-Control: private, no-cache="Set-Cookie"
Content-Type: text/html; charset=utf-8
Content-Length: 16975
Response is the actual login webpage.  Omitted for obvious reasons.

コードをステップ実行すると、このリクエスト/レスポンスは、postStream.Write の呼び出しの直後に生成されます。

リクエスト:

POST http://Withheld/Login.aspx HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: withheld
Content-Length: 2109
Expect: 100-continue

__LASTFOCUS=&ctrlCreateNewPassword_scriptManagerMaster_HiddenField=&__EVENTTARGET=&__EVENTARGUMENT=&__VIEWSTATE=%2fwEPDwUJNTE1NTIxNjkxD2QWAgIDD2QWBgIDDxYCHgVjbGFzcwUQaGVhZGVyX2Jhbm5lcl9lbhYCAgEPFgQeB29uY2xpY2sFI3dpbmRvdy5sb2NhdGlvbj0naHR0cDovL3d3dy5tZG0uY2EnHwAFFmhlYWRlcl9iYW5uZXJfZW5fc21hbGxkAgUPZBYQAgcPDxYEHhdQYXJ0aWFsUmVuZGVyaW5nQ2hlY2tlZGceGUlzUGFydGlhbFJlbmRlcmluZ0VuYWJsZWRoZGQCCQ8PFgQfAmcfA2hkZAIPDw8WBB8CZx8DaGRkAhEPDxYCHg1PbkNsaWVudENsaWNrBcEBamF2YXNjcmlwdDpQYWdlX0NsaWVudFZhbGlkYXRlKCdMb2dpbkN0cmwnKTsgaWYgKFBhZ2VfSXNWYWxpZCkgeyBMb2dpbkJ1dHRvbi5zdHlsZS52aXNpYmlsaXR5ID0gJ2hpZGRlbic7IExvZ2luQnV0dG9uLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7IExvZ2luQnV0dG9uRGlzYWJsZWQuc3R5bGUudmlzaWJpbGl0eSA9ICd2aXNpYmxlJzsgfWRkAhkPDxYCHgRUZXh0Bc0BSWYgeW91IHJlcXVpcmUgYXNzaXN0YW5jZSwgb3VyIE1EIE9ubGluZSBTdXBwb3J0IFNwZWNpYWxpc3RzIGNhbiBiZSByZWFjaGVkIGF0ICg4NzcpIDQzMS0wMzMwIG9yIGJ5IGUtbWFpbCBhdCA8YSBocmVmPSJtYWlsdG86d2Vic3VwcG9ydEBjbWEuY2EiPndlYnN1cHBvcnRAY21hLmNhPC9hPi48YnI%2bPGJyPldlIGVuY291cmFnZSB5b3UgdG8gcmV2aWV3IHRoZWRkAhsPDxYCHwQFOXdpbmRvdy5vcGVuKCdodHRwOi8vMTkyLjE2OC4xNjUuMzIvbGVnYWwvJyk7cmV0dXJuIGZhbHNlO2RkAh8PDxYCHwQFRndpbmRvdy5vcGVuKCdodHRwOi8vMTkyLjE2OC4xNjUuMzIvc3lzdGVtLWVuaGFuY2VtZW50LycpO3JldHVybiBmYWxzZTtkZAIhDw8WAh8EBUZ3aW5kb3cub3BlbignaHR0cDovLzE5Mi4xNjguMTY1LjMyL3N5c3RlbS1lbmhhbmNlbWVudC8nKTtyZXR1cm4gZmFsc2U7ZGQCCQ9kFgICAQ9kFgICAg9kFgJmD2QWAgIBD2QWAgIdDw8WAh8EBfsBamF2YXNjcmlwdDpjdHJsQ3JlYXRlTmV3UGFzc3dvcmRfQ3JlYXRlTmV3UGFzc3dvcmRQdXNoQnV0dG9uLnN0eWxlLnZpc2liaWxpdHkgPSAnaGlkZGVuJzsgY3RybENyZWF0ZU5ld1Bhc3N3b3JkX0NyZWF0ZU5ld1Bhc3N3b3JkUHVzaEJ1dHRvbi5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnOyBjdHJsQ3JlYXRlTmV3UGFzc3dvcmRfQ3JlYXRlTmV3UGFzc3dvcmRQdXNoQnV0dG9uRGlzYWJsZWQuc3R5bGUudmlzaWJpbGl0eSA9ICd2aXNpYmxlJztkZBgBBR5fX0NvbnRyb2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WAQUMaWJ0bk1vcmVJbmZvdZmFXkMbPfVWPQYtreXvFt8Bck8%3d&__PREVIOUSPAGE=1aYW5DqTKrT4ieGPkHcnrQLIq8lEcSIVkql1EugwSQNV_5102t5D7QDmOnuQFA4Tz9Mh5-CEYpkRngMROFFeeAG12Ss1&__EVENTVALIDATION=%2fwEWCQKKr%2bXcBgKvruq2CALSxeCRDwL%2bjNCfDwKH8YSKBgKN6O7XCwKz9P38DALl3I74DwLWxI74D6Nz%2f2bCBFC%2bM9glZmEyM%2byOCTZg&UserName=user01&Password=password99&LoginButton=Log+in

応答:

HTTP/1.1 302 Found
Connection: close
Date: Mon, 04 Feb 2013 16:36:55 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Location: /Default.aspx?locale=en
Set-Cookie: .EXTASPXAUTH=65BB5BFDD274F730E26CAEAAEB417792A764E7B8E8C6C9AC8C47FA97EF35DFACF551A53EAA6EA67D868C8A9BF55EBA758A5E724C58269028EE48F56268A204CBED19B60FC1AF58892989D9546202C037E97BF0EEE6A6281FF5EEA461BC30C5C7A71DFD64027AEB796D3FD21AE97ECFB16FF0F95C; path=/; HttpOnly
Cache-Control: private, no-cache="Set-Cookie"
Content-Type: text/html; charset=utf-8
Content-Length: 140

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="/Default.aspx?locale=en">here</a>.</h2>
</body></html>

上記の応答には認証 Cookie が含まれていることに注意してください。次に、その Cookie を取得する目的で次のコード行を実行します。

HttpWebResponse httpResponse = request2.GetResponse() as HttpWebResponse;

ただし、代わりに、次の要求/応答がフィドラーで生成されます。

リクエスト:

GET http://withtheld/Default.aspx?locale=en HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: withheld

応答:

HTTP/1.1 302 Found
Connection: close
Date: Mon, 04 Feb 2013 16:37:38 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Location: /Login.aspx?ReturnUrl=%2fDefault.aspx%3flocale%3den&locale=en
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 182

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="/Login.aspx?ReturnUrl=%2fDefault.aspx%3flocale%3den&amp;locale=en">here</a>.</h2>
</body></html>

これは、現在 httpResponse に含まれている応答だと思います。ログインが完了した後、実際に Cookie を取得して別の保護されたページを要求するにはどうすればよいですか?

ありがとう!

4

2 に答える 2

2

さて、ここで2つの問題があったことがわかりました。1つは、これを呼び出す必要があることです:

request.AllowAutoRedirect = false

これにより、フレームワークが認証 Cookie を含む応答をスキップするだけでなく、実際に必要な応答が返されます。

もう 1 つの問題は、CookieContainer の新しいインスタンスを作成し、それをリクエストに割り当てる必要があることです。Response.Cookies には Cookie が含まれていません。独自のコンテナーを割り当てるとすぐに、応答が行われた後にデータが取り込まれます。どうしてか分かりません。

于 2013-02-05T22:02:55.090 に答える
1

ログインすると、認証トークンが Cookie としてサーバーからクライアントに送信されます。この Cookie を保存し、今後のすべてのリクエストで再送信する必要があります。Cookie を再送信することで、特定のユーザーとして認証されたことをサーバーに伝えます。

ログイン後に応答として送信された Cookie を取得するには:

HttpCookieCollection loginResponseCookies = Response.Cookies;

このコレクションには、認証 Cookie、セッション Cookie などが含まれます。

次に、後続のすべてのリクエストでこれらの Cookie を再送信するだけで、サーバーは結果としてユーザーを認証します。

foreach(HttpCookie loginResponseCookie in loginResponseCookies)
{
    Response.Cookies.Add(loginResponseCookie);
}
于 2013-02-04T18:30:44.897 に答える