无法验证网站,禁止访问

Unable to authenticate to website, Forbidden

问题

我正在尝试在此网站上验证自己的身份:https://www.peddemoeek.nl/

然而,到目前为止所有尝试都失败并返回了 ErrorCode Forbidden,WebClient 将其处理为 WebException.

环境

预期结果

网站响应登录成功

正常的浏览器登录结果

程序登录结果

代码

AdvancedWebClient.cs

public class AdvancedWebClient : WebClient
{
    public AdvancedWebClient()
    {
        this.CookieContainer = new CookieContainer();
    }

    public static NameValueCollection ParseFormFields(string aHTML)
    {
        if (aHTML == null)
        {
            throw new ArgumentNullException("Invalid argument");
        }

        HtmlDocument document = new HtmlDocument();
        document.OptionAutoCloseOnEnd = true;
        document.LoadHtml(aHTML);

        NameValueCollection result = new NameValueCollection();

        HtmlNodeCollection inputNodes = document.DocumentNode.SelectNodes("//input[@name]");
        foreach (HtmlNode node in inputNodes)
        {
            HtmlAttribute name = node.Attributes["name"];
            HtmlAttribute value = node.Attributes["value"];

            if (value == null)
            {
                result.Add(name.Value, string.Empty);
            }
            else
            {
                result.Add(name.Value, value.Value.Replace('`', '\"'));
            }
        }

        return result;
    }

    public static bool MatchXPath(string aHTML, string aXPath)
    {
        if (aHTML == null || aXPath == null)
        {
            throw new ArgumentNullException("Invalid argument(s)");
        }

        HtmlDocument document = new HtmlDocument();
        document.OptionAutoCloseOnEnd = true;
        document.LoadHtml(aHTML);

        return (document.DocumentNode.SelectSingleNode(aXPath) != null);
    }

    protected override WebRequest GetWebRequest(Uri aAddress)
    {
        HttpWebRequest request = base.GetWebRequest(aAddress) as HttpWebRequest;

        if (request != null)
        {
            request.CookieContainer = this.CookieContainer;
        }

        return request;
    }

    protected override WebResponse GetWebResponse(WebRequest aRequest)
    {
        WebResponse response = base.GetWebResponse(aRequest);

        this.ProcessResponse(response);

        return response;
    }

    protected override WebResponse GetWebResponse(WebRequest aRequest, IAsyncResult aResult)
    {
        WebResponse response = base.GetWebResponse(aRequest, aResult);

        this.ProcessResponse(response);

        return response;
    }

    private void ProcessResponse(WebResponse aResponse)
    {
        HttpWebResponse response = aResponse as HttpWebResponse;

        if (response != null)
        {
            foreach (Cookie cookie in response.Cookies)
            {
                this.CookieContainer.SetCookies(response.ResponseUri, cookie.Name + '=' + cookie.Value);
            }
        }
    }

    public CookieContainer CookieContainer
    {
        get;
        private set;
    }
}

SecuredWebsite.cs

public enum LoginResult
{
    LOGIN_RESULT_OK,
    LOGIN_RESULT_INVALID_CREDENTIALS,
    LOGIN_RESULT_ERROR
}

public abstract class SecuredWebsite : IDisposable
{
    public SecuredWebsite(string aBaseAddress)
    {
        if (aBaseAddress == null)
        {
            throw new ArgumentNullException("Invalid argument");
        }

        this.mClient = new AdvancedWebClient();
        this.disposedValue = false;

        this.mClient.Headers[HttpRequestHeader.AcceptCharset] = "UTF-8";
        this.mClient.BaseAddress = aBaseAddress;
    }

    public void Dispose()
    {
        Dispose(true);
    }

    public abstract LoginResult Login(string aUsername, string aPassword);

    protected virtual void Dispose(bool disposing)
    {
        if (this.disposedValue == false)
        {
            if (disposing)
            {
                this.mClient.Dispose();
            }

            this.disposedValue = true;
        }
    }

    protected AdvancedWebClient mClient;

    private bool disposedValue;
}

PeddemoeekWebsite.cs

public class PeddemoeekWebsite : SecuredWebsite
{
    public PeddemoeekWebsite() :
        base("https://www.peddemoeek.nl/")
    {
        base.mClient.Headers[HttpRequestHeader.CacheControl] = "max-age=0";
        base.mClient.Headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
        base.mClient.Headers[HttpRequestHeader.AcceptLanguage] = "nl-NL,nl;q=0.8,en-US;q=0.6,en;q=0.4";
        base.mClient.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36";
        base.mClient.Headers[HttpRequestHeader.AcceptEncoding] = "";
        base.mClient.Headers["Upgrade-Insecure-Requests"] = "1";
        base.mClient.Headers[HttpRequestHeader.Referer] = "https://www.peddemoeek.nl/";
        base.mClient.Headers["Origin"] = "https://www.peddemoeek.nl";
    }

    public override LoginResult Login(string aUsername, string aPassword)
    {
        if (aUsername == null || aPassword == null)
        {
            throw new ArgumentNullException("Invalid argument(s)");
        }

        LoginResult result = LoginResult.LOGIN_RESULT_OK;

        try
        {
            byte[] responseData = base.mClient.DownloadData("/");
            if (responseData == null)
            {
                result = LoginResult.LOGIN_RESULT_ERROR;
            }
            else
            {
                string response = Encoding.UTF8.GetString(responseData);

                NameValueCollection formFields = AdvancedWebClient.ParseFormFields(response);

                formFields.Set("username", aUsername);
                formFields.Set("passwd", aPassword);
                formFields.Set("remember", "no");
                formFields.Set("Submit", "");

                responseData = base.mClient.UploadValues("/component/comprofiler/login.html", formFields);
                if (responseData == null)
                {
                    result = LoginResult.LOGIN_RESULT_ERROR;
                }
                else
                {
                    response = Encoding.UTF8.GetString(responseData);
                    // TODO: handle response
                }
            }
        }
        catch (WebException)
        {
            result = LoginResult.LOGIN_RESULT_ERROR;
        }

        return result;
    }
}

显然通过 WebClientHeaders 属性 设置用户代理并没有设置它。我不得不把它放在 WebRequest 级别:

protected override WebRequest GetWebRequest(Uri aAddress)
    {
        HttpWebRequest request = base.GetWebRequest(aAddress) as HttpWebRequest;

        if (request != null)
        {
            request.CookieContainer = this.CookieContainer;
            request.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36";
            request.Headers[HttpRequestHeader.AcceptCharset] = "UTF-8";
        }

        return request;
    }