简体   繁体   English

在C#中使用Wininet设置代理用户名和密码

[英]Set Proxy UserName and Password using Wininet in C#

This is my first question in Stack Overflow. 这是我在Stack Overflow中的第一个问题。 I have had great help from this site. 我从这个网站得到了很大的帮助。

I am working on an application in C# on .NET 2010. I am trying to set system wide proxy server for http requests. 我正在使用.NET 2010上的C#应用​​程序。我正在尝试为http请求设置系统范围的代理服务器。 Proxy Server is a Squid based proxy with "basic" authentication enabled. Proxy Server是一个基于Squid的代理,启用了“基本”身份验证。 I have been able to set the proxy of IE. 我已经能够设置IE的代理。

Now after proxy is set in IE, IE asks for username and password for proxy, and now I am trying to automate this functionality, and for last 1 week I have been unable to get it working and have been searching internet but still no success. 现在在IE中设置代理后,IE要求代理的用户名和密码,现在我正在尝试自动执行此功能,并且在过去的一周内我一直无法使其工作并且一直在搜索互联网但仍然没有成功。

Below is the code I am using to set IE proxy. 下面是我用来设置IE代理的代码。

public static bool SetProxy(string strProxy, string username, string password, string exceptions)
    {

        InternetPerConnOptionList list = new InternetPerConnOptionList();

        int optionCount = string.IsNullOrEmpty(strProxy) ? 1 : (string.IsNullOrEmpty(exceptions) ? 2 : 3);
        InternetConnectionOption[] options = new InternetConnectionOption[optionCount];
        // USE a proxy server ...
        options[0].m_Option = PerConnOption.INTERNET_PER_CONN_FLAGS;
        options[0].m_Value.m_Int = (int)((optionCount < 2) ? PerConnFlags.PROXY_TYPE_DIRECT : (PerConnFlags.PROXY_TYPE_DIRECT | PerConnFlags.PROXY_TYPE_PROXY));
        // use THIS proxy server
        if (optionCount > 1)
        {
            options[1].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_SERVER;
            options[1].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(strProxy);
            // except for these addresses ...
            if (optionCount > 2)
            {
                options[2].m_Option = PerConnOption.INTERNET_PER_CONN_PROXY_BYPASS;
                options[2].m_Value.m_StringPtr = Marshal.StringToHGlobalAuto(exceptions);
            }
        }

        // default stuff
        list.dwSize = Marshal.SizeOf(list);
        list.szConnection = IntPtr.Zero;
        list.dwOptionCount = options.Length;
        list.dwOptionError = 0;


        int optSize = Marshal.SizeOf(typeof(InternetConnectionOption));
        // make a pointer out of all that ...
        IntPtr optionsPtr = Marshal.AllocCoTaskMem(optSize * options.Length);
        // copy the array over into that spot in memory ...
        for (int i = 0; i < options.Length; ++i)
        {
            IntPtr opt = new IntPtr(optionsPtr.ToInt32() + (i * optSize));
            Marshal.StructureToPtr(options[i], opt, false);
        }

        list.options = optionsPtr;

        // and then make a pointer out of the whole list
        IntPtr ipcoListPtr = Marshal.AllocCoTaskMem((Int32)list.dwSize);
        Marshal.StructureToPtr(list, ipcoListPtr, false);

        // and finally, call the API method!
        int returnvalue = NativeMethods.InternetSetOption(IntPtr.Zero,
           InternetOption.INTERNET_OPTION_PER_CONNECTION_OPTION,
           ipcoListPtr, list.dwSize) ? -1 : 0;
        if (returnvalue == 0)
        {  // get the error codes, they might be helpful
            returnvalue = Marshal.GetLastWin32Error();
        }
        // FREE the data ASAP
        Marshal.FreeCoTaskMem(optionsPtr);
        Marshal.FreeCoTaskMem(ipcoListPtr);
        if (returnvalue > 0)
        {  // throw the error codes, they might be helpful
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }

        return (returnvalue < 0);
    }
}

#region WinInet structures
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetPerConnOptionList
{
    public int dwSize;               // size of the INTERNET_PER_CONN_OPTION_LIST struct
    public IntPtr szConnection;         // connection name to set/query options
    public int dwOptionCount;        // number of options to set/query
    public int dwOptionError;           // on error, which option failed
    //[MarshalAs(UnmanagedType.)]
    public IntPtr options;
};

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct InternetConnectionOption
{
    static readonly int Size;
    public PerConnOption m_Option;
    public InternetConnectionOptionValue m_Value;
    static InternetConnectionOption()
    {
        InternetConnectionOption.Size = Marshal.SizeOf(typeof(InternetConnectionOption));
    }

    // Nested Types
    [StructLayout(LayoutKind.Explicit)]
    public struct InternetConnectionOptionValue
    {
        // Fields
        [FieldOffset(0)]
        public System.Runtime.InteropServices.ComTypes.FILETIME m_FileTime;
        [FieldOffset(0)]
        public int m_Int;
        [FieldOffset(0)]
        public IntPtr m_StringPtr;
    }
}
#endregion

#region WinInet enums
//
// options manifests for Internet{Query|Set}Option
//
public enum InternetOption : uint
{
    INTERNET_OPTION_PER_CONNECTION_OPTION = 75
}

//
// Options used in INTERNET_PER_CONN_OPTON struct
//
public enum PerConnOption
{
    INTERNET_PER_CONN_FLAGS = 1, // Sets or retrieves the connection type. The Value member will contain one or more of the values from PerConnFlags 
    INTERNET_PER_CONN_PROXY_SERVER = 2, // Sets or retrieves a string containing the proxy servers.  
    INTERNET_PER_CONN_PROXY_BYPASS = 3, // Sets or retrieves a string containing the URLs that do not use the proxy server.  
    INTERNET_PER_CONN_AUTOCONFIG_URL = 4//, // Sets or retrieves a string containing the URL to the automatic configuration script.  
}

//
// PER_CONN_FLAGS
//
[Flags]
public enum PerConnFlags
{
    PROXY_TYPE_DIRECT = 0x00000001,  // direct to net
    PROXY_TYPE_PROXY = 0x00000002,  // via named proxy
    PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,  // autoproxy URL
    PROXY_TYPE_AUTO_DETECT = 0x00000008   // use autoproxy detection
}
#endregion

internal static class NativeMethods
{
    [DllImport("WinInet.dll", SetLastError = true, CharSet = CharSet.Auto)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool InternetSetOption(IntPtr hInternet, InternetOption dwOption, IntPtr lpBuffer, int dwBufferLength);
}

Any help in getting this functionality working would be greatly appreciated. 任何有关使此功能正常工作的帮助将不胜感激。

Regards, Mudasir Mirza. 此致,Mudasir Mirza。

When you set a proxy for WinINET, there's no way to store a "global" proxy username and password that all clients will benefit from. 当您为WinINET设置代理时,无法存储所有客户端将从中受益的“全局”代理用户名和密码。 You can only cache this username/password on a per-process basis. 您只能基于每个进程缓存此用户名/密码。 In the process, you can use the InternetSetOption API to provide the username and password. 在此过程中,您可以使用InternetSetOption API提供用户名和密码。 This will only set the password for WinINET, and not for .NET or other HTTP stacks. 这只会设置WinINET的密码,而不是.NET或其他HTTP堆栈的密码。

I got the similar problem with WebBrowser control while dealing with authentication and irritating "Windows security" window. 在处理身份验证和恼人的“Windows安全”窗口时,我遇到了与WebBrowser控件类似的问题。 First, set proxy address with WinINET and then call navigate method with your credentials. 首先,使用WinINET设置代理地址,然后使用您的凭据调用navigate方法。 It helps to store proxy credentials per one process: 它有助于为每个进程存储代理凭据:

WebBrowser.Navigate("http://user:pass@geoip.hidemyass.com/");

WinINET method sets proxy address perfect, however your code uses INTERNET_OPTION_PER_CONNECTION_OPTION which is not suitable for your "global proxy" idea (as @EricLaw said). WinINET方法设置代理地址完美,但是你的代码使用INTERNET_OPTION_PER_CONNECTION_OPTION ,这不适合你的“全局代理”想法(如@EricLaw所说)。 Try to work around with INTERNET_OPTION_PROXY ( documentaion ) 尝试使用INTERNET_OPTION_PROXYdocumentaion

Furthermore there are four different approaches with no direct solution. 此外,有四种不同的方法 ,没有直接的解决方案。 But they are very handy. 但它们非常方便。

Have a look at the WebProxy class and see if that allows you to do what you want? 看看WebProxy类,看看是否允许你做你想做的事情?

use it in the following way (I'm going to assume that exceptions are separated by a ';'): 以下列方式使用它(我将假设异常由';'分隔):

public static void SetProxy(string proxyAddress, string userName, string password, string exceptions)
{
    var credential = new NetworkCredential(userName, password);

    string[] bypassList = null;

    if (!string.IsNullOrEmpty(exceptions))
    {
        bypassList = exceptions.Split(';');
    }

    WebRequest.DefaultWebProxy = new WebProxy(proxyAddress, true, bypassList, credential);
}

to call the method: 调用方法:

SetProxy("http://proxy:8080", "user", "password", "http://site1;http://site2");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM