문제

프로그래밍 방식으로 wordpress 관리 패널에서 일부 작업을 수행해야 하지만 C# 및 HttpWebRequest를 사용하여 Wordpress에 로그인하는 방법을 관리할 수 없습니다.

내가하는 일은 다음과 같습니다.

private void button1_Click(object sender, EventArgs e)
        {
            string url = "http://localhost/wordpress/wp-login.php";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            CookieContainer cookies = new CookieContainer();

            SetupRequest(url, request, cookies);
            //request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            //request.Headers["Accept-Language"] = "uk,ru;q=0.8,en-us;q=0.5,en;q=0.3";
            //request.Headers["Accept-Encoding"] = "gzip,deflate";
            //request.Headers["Accept-Charset"] = "windows-1251,utf-8;q=0.7,*;q=0.7";


            string user = "test";
            string pwd = "test";

            request.Credentials = new NetworkCredential(user, pwd);

            string data = string.Format(
                "log={0}&pwd={1}&wp-submit={2}&testcookie=1&redirect_to={3}",
                user, pwd, 
                System.Web.HttpUtility.UrlEncode("Log In"),
                System.Web.HttpUtility.UrlEncode("http://localhost/wordpress/wp-admin/"));

            SetRequestData(request, data);

            ShowResponse(request);
}

private static void SetupRequest(string url, HttpWebRequest request, CookieContainer cookies)
        {
            request.CookieContainer = cookies;
            request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; uk; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)";
            request.KeepAlive = true;
            request.Timeout = 120000;
            request.Method = "POST";
            request.Referer = url;
            request.ContentType = "application/x-www-form-urlencoded";
        }

        private void ShowResponse(HttpWebRequest request)
        {
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            responseTextBox.Text = (((HttpWebResponse)response).StatusDescription);
            responseTextBox.Text += "\r\n";
            StreamReader reader = new StreamReader(response.GetResponseStream());
            responseTextBox.Text += reader.ReadToEnd();
        }

        private static void SetRequestData(HttpWebRequest request, string data)
        {
            byte[] streamData = Encoding.ASCII.GetBytes(data);
            request.ContentLength = streamData.Length;

            Stream dataStream = request.GetRequestStream();
            dataStream.Write(streamData, 0, streamData.Length);
            dataStream.Close();
        }

그러나 불행하게도 나는 로그인 페이지의 HTML 소스 코드만 얻었고 쿠키에는 세션 ID가 포함되지 않은 것 같습니다.해당 코드 이후에 수행하는 모든 요청은 로그인 페이지의 HTML 소스도 반환하므로 올바르게 로그인하지 않았다고 가정할 수 있습니다.

누구든지 내가 그 문제를 해결하도록 도와주거나 실제 사례를 제시할 수 있습니까?


제가 달성하고 싶은 가장 중요한 것은 Wordpress용 Nextgen Gallery 플러그인에서 새 이미지를 검색하는 것입니다.XML-RPC 방식으로 그렇게 할 수 있나요?

미리 감사드립니다.

도움이 되었습니까?

해결책 3

모두에게 감사 드려요.소켓을 사용할 때만 작동하도록 하는 방법을 관리했습니다.Wordpress는 여러 가지를 보냅니다. 세트쿠키 헤더는 있지만 HttpWebRequest 해당 헤더의 인스턴스를 하나만 처리하므로 일부 쿠키가 손실됩니다.소켓을 사용할 때 필요한 모든 쿠키를 얻고 관리자 패널에 로그인할 수 있습니다.

다른 팁

WordPress에서는 리디렉션을 구현하므로 페이지를 떠나는 것(리디렉션)으로 인해 웹 요청이 적절한 쿠키를 얻을 수 없습니다.

관련 쿠키를 얻으려면 리디렉션을 방지해야 합니다.

request.AllowAutoRedirect = false;

로그인을 위해 쿠키 컨테이너를 사용하는 것보다.

다음 코드를 참조하세요.(Albahari의 C# 책의 예를 기반으로 함)

        string loginUri = "http://www.someaddress.com/wp-login.php";
        string username = "username";
        string password = "pass";
        string reqString = "log=" + username + "&pwd=" + password;
        byte[] requestData = Encoding.UTF8.GetBytes(reqString);

        CookieContainer cc = new CookieContainer();
        var request = (HttpWebRequest)WebRequest.Create(loginUri);
        request.Proxy = null;
        request.AllowAutoRedirect = false;
        request.CookieContainer = cc;
        request.Method = "post";

        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = requestData.Length;
        using (Stream s = request.GetRequestStream())
            s.Write(requestData, 0, requestData.Length);

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            foreach (Cookie c in response.Cookies)
                Console.WriteLine(c.Name + " = " + c.Value);
        }

        string newloginUri = "http://www.someaddress.com/private/";
        HttpWebRequest newrequest = (HttpWebRequest)WebRequest.Create(newloginUri);
        newrequest.Proxy = null;
        newrequest.CookieContainer = cc;
        using (HttpWebResponse newresponse = (HttpWebResponse)newrequest.GetResponse())
        using (Stream resSteam = newresponse.GetResponseStream())
        using (StreamReader sr = new StreamReader(resSteam))
            File.WriteAllText("private.html", sr.ReadToEnd());
        System.Diagnostics.Process.Start("private.html");

다른 사람들이 이 내용이 도움이 될지는 모르겠지만 저는 WordPress API를 사용하여 로그인했습니다.cron 작업의 일부로 밤에 "로그인"하여 일부 작업을 수행하는 사용자(CRON_USR)를 만들었습니다.코드는 다음과 같습니다.

require(dirname(__FILE__) . '/wp-load.php' );
$user = wp_authenticate(CRON_USR, CRON_PWD);
wp_set_auth_cookie($user->ID, true, $secure_cookie); //$secure_cookie is an empty string
do_action('wp_login', CRON_USR);
wp_redirect('http://www.mysite.com/wp-admin/');
NameValueCollection loginData = new NameValueCollection();
loginData.Add("username", "your_username");
loginData.Add("password", "your_password");

WebClient client = new WebClient();
string source = Encoding.UTF8.GetString(client.UploadValues("http://www.site.com/login", loginData));

string cookie = client.ResponseHeaders["Set-Cookie"];

귀하의 코드에는 명백한 문제가 없습니다. 죄송합니다.하지만 Wordpress에는 관리 인터페이스에서 활성화해야 하는 XML-RPC 인터페이스가 있습니다.나는 이 인터페이스를 위해 Python 스크립트를 작성했는데 정말 매력적이었습니다.

내 WordPress.com 계정(SSL로 보호됨)으로 이 작업을 시도했습니다.가장 쉬운 방법은 .NET 소켓을 사용하여 HTTP "Set-Cookie" 헤더를 가져온 다음 헤더를 .NET 쿠키 개체로 구문 분석한 다음 HttpWebRequest용 쿠키와 함께 CookieContainer를 사용하는 것임을 발견했습니다.

소켓을 통해 SSL을 사용하는 가장 쉬운 방법은 소켓에 바인딩된 NetworkStream을 통해 SslStream을 구현하는 것입니다.

예:

private void LogIn()
    {
        string fulladdress = "hostname.wordpress.com";
        string username = HttpUtility.UrlEncode("username");
        string password = HttpUtility.UrlEncode("password");

        string formdata = "log={0}&pwd={1}&redirect_to=http%3A%2F%2F{2}%2Fwp-admin%2F&testcookie=1";
        formdata = string.Format(formdata, username, password, fulladdress);
        IPHostEntry entry = Dns.GetHostEntry(fulladdress);


        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        s.Connect(entry.AddressList[0], 443);

        NetworkStream ns = new NetworkStream(s);

        System.Net.Security.SslStream ssl = new System.Net.Security.SslStream(ns);
        byte[] data = Encoding.UTF8.GetBytes(String.Format(WpfApplication2.Properties.Resources.LogRequest, "https://" + fulladdress, fulladdress, form.Length, username, password));

        ssl.AuthenticateAsClient(fulladdress);
        ssl.Write(data, 0, data.Length);

        StringBuilder sb = new StringBuilder();
        byte[] resp = new byte[128];
        int i = 0;
        while (ssl.Read(resp, 0, 128) > 0)
        {
            sb.Append(Encoding.UTF8.GetString(resp));
        }

        List<String> CookieHeaders = new List<string>();
        foreach (string header in sb.ToString().Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
        {
            if (header.StartsWith("Set-Cookie"))
            {
                CookieHeaders.Add(header.Replace("Set-Cookie: ", ""));
            }
        }

        CookieContainer jar = new CookieContainer();
        foreach (string cook in CookieHeaders)
        {
            string name, value, path, domain;
            name = value = path = domain = "";

            string[] split = cook.Split(';');
            foreach (string part in split)
            {
                if (part.StartsWith(" path="))
                {
                    path = part.Replace(" path=", "");
                }
                if (part.StartsWith(" domain="))
                {
                    domain = part.Replace(" domain=", "");
                }
                if (!part.StartsWith(" path=") && !part.StartsWith(" domain=") && part.Contains("="))
                {
                    name = part.Split('=')[0];
                    value = part.Split('=')[1];
                }
            }

            jar.Add(new Cookie(name, value, path, domain));
        }

        HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://" + fulladdress + "/wp-admin/index.php");
        req.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3";
        req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        req.KeepAlive = false;
        req.AllowAutoRedirect = false;
        req.Referer = "https://" + fulladdress + "/wp-login.php";
        req.ContentType = "application/x-www-form-urlencoded";
        req.CookieContainer = jar;
        req.AllowAutoRedirect = true;
        req.AutomaticDecompression = DecompressionMethods.GZip;
        req.Method = "GET";
        req.Timeout = 30000;

        HttpWebResponse response = (HttpWebResponse)req.GetResponse();

        using (System.IO.StreamReader sr = new System.IO.StreamReader(response.GetResponseStream(), Encoding.UTF8))
        {
            MessageBox.Show(sr.ReadToEnd());
        }
    }

코드는 그다지 효율적이지는 않지만 관리 인터페이스에 로그인하는 프로세스를 보여줍니다.

도움이 되길 바랍니다 :)

TomerBu가 나에게 가장 적합한 답변을 제공하지만 뭔가 빠졌습니다.

그의 코드에서는 다음을 대체합니다.

 foreach (Cookie c in response.Cookies)
            Console.WriteLine(c.Name + " = " + c.Value);

~에 의해

if (response.Cookies != null)
    {
        foreach (Cookie currentcook in response.Cookies)
             request.CookieContainer.Add(currentcook); //This is the key !!!
    }

다음으로 향후 요청을 위해서는 CookieContainer를 재사용해야 합니다.

토메르부의 대답은 다음 추가 사항으로 나에게 적합합니다.웹사이트에 SSL 인증서를 설치하고, TLS1.2에 대한 지원을 추가하고, 이것이 작동하려면 UserAgent를 설정해야 했습니다.TLS1.2가 없으면 웹 서버가 내 연결 요청을 즉시 거부했습니다.SSL 인증서가 없으면 WordPress 사이트는 로그인에 성공한 경우에도 후속 WebRequest에 대해 내 C# 봇이 로그인되는 것으로 간주하지 않았습니다.

*** TLS에 대한 중요 참고 사항:나는 보안 프로토콜 초보자이고 나에게 도움이 되는 것만 제공하고 있습니다..NET 4.7.2 개발자 팩을 설치하고 C# 프로젝트의 대상 프레임워크를 .NET 4.7.2로 변경했지만 여전히 아래와 같이 ServicePointManager.SecurityProtocol을 수정해야 했습니다..NET 업데이트 및 비트별 ORed 문에서 여러 TLS 버전 지정을 포함한 모범 사례를 찾으려면 검색하세요.

// Add support for TLS 1.2 (note bitwise OR)
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

...
request.Proxy = null;
request.AllowAutoRedirect = false;
request.CookieContainer = cc;
request.Method = "post";

// Add UserAgent
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1";
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top