通过 httpwebrequest 登录 strava 失败

strava login via httpwebrequest failed

您好,我正在尝试通过 https://www.strava.com/session with HttpWebrequest but it doesn't log me in. It gives me an response of 302 which is good but it never redirect me to https://www.strava.com/dashboard 登录。

这是我正在使用的代码

Http客户端:

public class HttpClient
{

    private const string UserAgent = "Mozilla/5.0";

    public CookieCollection CookieCollection;

    public HttpWebRequest WebRequest;
    public HttpWebResponse WebResponse;
    public int code { get; set; }
    public string location { get; set; }


    public string PostData(string url, string postData, string refer = "")
    {

        WebRequest = (HttpWebRequest)System.Net.WebRequest.Create(url);
        WebRequest.UserAgent = UserAgent;
        WebRequest.Referer = refer;

        WebRequest.AllowAutoRedirect =false;
        WebRequest.Timeout = 10000;
        WebRequest.KeepAlive = true;
        WebRequest.CookieContainer = new CookieContainer();

        if (CookieCollection != null && CookieCollection.Count > 0)
        {
            WebRequest.CookieContainer.Add(CookieCollection);

        }


        WebRequest.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
        WebRequest.Method = "POST";

        try
        {
            var postBytes = Encoding.UTF8.GetBytes(postData);
            WebRequest.ContentLength = postBytes.Length;
            var postDataStream = WebRequest.GetRequestStream();
            postDataStream.Write(postBytes, 0, postBytes.Length);
            postDataStream.Close();
            try
            {
                WebResponse = (HttpWebResponse)WebRequest.GetResponse();

                this.code = (int)WebResponse.StatusCode;
                this.location = WebResponse.Headers["Location"];
                if (WebResponse.StatusCode == HttpStatusCode.OK ||WebResponse.StatusCode == HttpStatusCode.Redirect)
                {


                    WebResponse.Cookies = WebRequest.CookieContainer.GetCookies(WebRequest.RequestUri);

                    if (WebResponse.Cookies.Count > 0)
                    {

                        if (CookieCollection == null)
                        {
                            CookieCollection = WebResponse.Cookies;
                        }
                        else
                        {
                            foreach (Cookie oRespCookie in WebResponse.Cookies)
                            {
                                var bMatch = false;
                                foreach (
                                    var oReqCookie in
                                        CookieCollection.Cast<Cookie>()
                                            .Where(oReqCookie => oReqCookie.Name == oRespCookie.Name))
                                {
                                    oReqCookie.Value = oRespCookie.Value;
                                    bMatch = true;
                                    break;
                                }
                                if (!bMatch)
                                    CookieCollection.Add(oRespCookie);
                            }
                        }
                    }

                    var reader = new StreamReader(WebResponse.GetResponseStream());
                    var responseString = reader.ReadToEnd();
                    reader.Close();
                    return responseString;
                }
            }
            catch (WebException wex)
            {
                if (wex.Response != null)
                {
                    using (var errorResponse = (HttpWebResponse)wex.Response)
                    {
                        using (var reader = new StreamReader(errorResponse.GetResponseStream()))
                        {
                            var error = reader.ReadToEnd();
                            return error;
                        }
                    }
                }
            }
        }

        catch (Exception ex)
        {

            Console.WriteLine(ex.Message);
        }
        return "Error in posting data" ;
    }


    public string GetData(string url, string post = "")
    {

        var responseStr = string.Empty;
        WebRequest = (HttpWebRequest)System.Net.WebRequest.Create(url);
        WebRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";
        WebRequest.Method = "GET";

        WebRequest.KeepAlive = true;
        WebRequest.Credentials = CredentialCache.DefaultCredentials;
        WebRequest.UserAgent = UserAgent;

        WebRequest.CookieContainer = new CookieContainer();
        if (CookieCollection != null && CookieCollection.Count > 0)
        {
            WebRequest.CookieContainer.Add(CookieCollection);
        }

        if (!string.IsNullOrEmpty(post))
        {
            var postBytes = Encoding.UTF8.GetBytes(post);
            WebRequest.ContentLength = postBytes.Length;
            var postDataStream = WebRequest.GetRequestStream();
            postDataStream.Write(postBytes, 0, postBytes.Length);
            postDataStream.Close();
        }


        WebResponse wresp = null;

        try
        {
            wresp = WebRequest.GetResponse();
            var downStream = wresp.GetResponseStream();
            if (downStream != null)
            {
                using (var downReader = new StreamReader(downStream))
                {
                    responseStr = downReader.ReadToEnd();
                }
            }
            return responseStr;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            if (wresp != null)
            {
                wresp.Close();
                wresp = null;
            }
        }
        finally
        {
            WebRequest = null;
        }
        return responseStr;
    }

}

获取crfs-token:

private string GetToken()
    {
        string token = "";
        String sourcestring = hc.GetData(loginURL);
        Regex metaTag = new Regex(@"<meta[\s]+[^>]*?name[\s]?=[\s""']+(.*?)[\s""']+content[\s]?=[\s""']+(.*?)[""']+.*?>");
        foreach (Match m in metaTag.Matches(sourcestring))
        {
            if (m.Groups[2].Value.Contains("token"))
            {
                continue;
            }

            token = m.Groups[2].Value;
        }

            return token;
    }

自定义键值对

private string PostParam(Dictionary<string, string> data)
    {
        var sb = new StringBuilder();
        var p = new List<string>();
        foreach (KeyValuePair<string, string> pair in data)
        {
            sb.Clear();
            sb.Append(pair.Key).Append("=").Append(pair.Value);
            p.Add(sb.ToString());
        }
        var pp = string.Join("&", p);
        return pp;
    }

登录:

 private HttpClient hc = new HttpClient();

字典数据 = new Dictionary();

        data.Add("utf8", "✓");
        data.Add("authenticity_token", GetToken());
        data.Add("plan", "");
        data.Add("email", "email");
        data.Add("password", "password");
        hc.PostData(sessionURL,WebUtility.UrlEncode(PostParam(data)), loginURL);

有人可以告诉我我做错了什么吗?如果我在浏览器中尝试登录 strava 时看到请求 header,它是一样的,但它仍然没有记录我。

我发现了问题。 您只需要对令牌(和 UTF8 字符)进行编码,而不是完整的 post 数据。

这对我有用(出于某种原因我需要 运行 代码两次)

// First time says "logged out"
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("utf8", WebUtility.UrlEncode("✓"));
string token = GetToken();
string tokenEncoded = WebUtility.UrlEncode(token);
data.Add("authenticity_token", tokenEncoded);
data.Add("plan", "");
data.Add("email", "youremail");
data.Add("password", "yourpwd");
data.Add("remember_me", "on");
string parameters = PostParam(data);
hc.PostData(sessionURL, parameters, loginURL);

// Second time logs in
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("utf8", WebUtility.UrlEncode("✓"));
string token = GetToken();
string tokenEncoded = WebUtility.UrlEncode(token);
data.Add("authenticity_token", tokenEncoded);
data.Add("plan", "");
data.Add("email", "youremail");
data.Add("password", "yourpwd");
data.Add("remember_me", "on");
string parameters = PostParam(data);
hc.PostData(sessionURL, parameters, loginURL);

注:

// Keep this on default value "true"
//WebRequest.AllowAutoRedirect = false;

备注:您可以使用此代码(参见我之前的post)在登录后更改activity的状态(隐私):

Dictionary<string, string> data2 = new Dictionary<string, string>();
data2.Add("utf8", WebUtility.UrlEncode("✓"));
string token2 = GetToken();
string tokenEncoded2 = WebUtility.UrlEncode(token2);
data2.Add("_method", "patch");
data2.Add("authenticity_token", tokenEncoded2);
data2.Add("activity%5Bvisibility%5D", "only_me"); // or "followers_only"
string parameters2 = PostParam(data2);
hc.PostData("https://www.strava.com/activities/youractivityID", parameters2, loginURL);