You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从C# WinForms应用调用受Membership验证的Web Handler

问题描述

我有一个ASP.NET Web Forms站点,通过多个Web Handler暴露数据库功能,这些Handler所在文件夹依赖Microsoft MembershipProvider模型做用户身份验证,已认证的站点用户访问完全正常。但主机服务商修改SQL Server政策后,数据库无法跨域访问,因此我编写了C# WinForms应用来管理站点数据,唯一途径就是调用站点的Web Handler。

若Handler放在未授权文件夹中,WinForms应用可正常调用;但将Handler移至受保护文件夹后,WebRequest/WebClient会被直接重定向到登录页。

我使用的RestClient类代码如下:

using System;
using System.IO;
using System.Net;

namespace MCTDesk.Web {
    public enum httpVerb {
        GET,
        POST,
        PUT,
        DELETE
    }

    public enum authenticationType {
        Basic,
        NTLM
    }

    public enum autheticationTechnique {
        RollYourOwn,
        NetworkCredential
    }

    class RestClient {
        public string endPoint { get; set; }
        public httpVerb httpMethod { get; set; }
        public authenticationType authType { get; set; }
        public autheticationTechnique authTech { get; set; }
        public string userName { get; set; }
        public string userPassword { get; set; }


        public RestClient ( ) {
            endPoint = string.Empty;
            httpMethod = httpVerb.GET;
        }

        public string makeRequest ( ) {
            string strResponseValue = string.Empty;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
            request.Method = httpMethod.ToString ( );
            String authHeader = System.Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(userName + ":" + userPassword));
            request.Headers.Add ( "Authorization", authType.ToString ( ) + " " + authHeader );
            HttpWebResponse response = null;
            try {
                response = ( HttpWebResponse ) request.GetResponse ( );
                //Process the response stream... (could be JSON, XML or HTML etc...)
                using ( Stream responseStream = response.GetResponseStream ( ) ) {
                    if ( responseStream != null ) {
                        using ( StreamReader reader = new StreamReader ( responseStream ) ) {
                            strResponseValue = reader.ReadToEnd ( );
                        }
                    }
                }
            }
            catch ( Exception ex ) {
                strResponseValue = "{\"errorMessages\":[\"" + ex.Message.ToString ( ) + "\"],\"errors\":{}}";
            }
            finally {
                if ( response != null ) {
                    ( ( IDisposable ) response ).Dispose ( );
                }
            }
            return strResponseValue;
        }
    }
}

调用代码:

private void LoadStats ( ) {
    RestClient rClient = new RestClient {
        endPoint = "https://[my site URL].com/handlers/gettodaystats.ashx",
        authTech = autheticationTechnique.RollYourOwn,
        authType = authenticationType.Basic,
        userName = "<username>",
        userPassword = "<password>"
    };
    string strResponse = string.Empty;
    strResponse = rClient.makeRequest ( );
    MessageBox.Show ( strResponse );
}

此前提问被判定为重复,但现有方案均无效,请问问题出在哪里?

问题分析与解决方法

核心问题:你使用的HTTP Basic认证和ASP.NET Web Forms默认的MembershipProvider表单认证完全不兼容,ASP.NET的表单认证系统不会识别你添加的Basic认证头,因此直接将请求重定向到登录页。

提供两种可行解决路径:

路径1:让Web Handler支持Basic认证(推荐)

修改ASP.NET站点配置,让受保护文件夹内的Handler支持Basic认证,并关联现有MembershipProvider验证用户身份。

  1. 在站点根Web.config的<system.web>节点下启用Basic认证模块:
<authentication mode="Forms">
  <!-- 保留原有Forms认证配置 -->
  <forms loginUrl="~/Login.aspx" timeout="2880" />
</authentication>
<authorization>
  <deny users="?" />
</authorization>
<httpModules>
  <add name="BasicAuthenticationModule" type="System.Web.Security.BasicAuthenticationModule" />
</httpModules>
  1. 针对Handler所在文件夹单独配置Basic认证(可通过<location>节点实现):
<location path="handlers">
  <system.web>
    <authorization>
      <deny users="?" />
    </authorization>
    <authentication mode="Basic">
      <basicAuthentication providerName="AspNetSqlMembershipProvider" realm="Your Site Realm" />
    </authentication>
  </system.web>
</location>

注意:若使用IIS 7及以上版本,需在IIS管理器中启用「Basic Authentication」功能,并确保应用池的.NET版本与站点匹配。

路径2:模拟表单认证流程

如果不想修改站点认证配置,可先模拟用户登录请求获取认证Cookie,后续调用Handler时携带该Cookie即可。

修改RestClient类添加Cookie支持:

using System;
using System.IO;
using System.Net;

namespace MCTDesk.Web {
    public enum httpVerb {
        GET,
        POST,
        PUT,
        DELETE
    }

    public enum authenticationType {
        Basic,
        NTLM
    }

    public enum autheticationTechnique {
        RollYourOwn,
        NetworkCredential
    }

    class RestClient {
        public string endPoint { get; set; }
        public httpVerb httpMethod { get; set; }
        public authenticationType authType { get; set; }
        public autheticationTechnique authTech { get; set; }
        public string userName { get; set; }
        public string userPassword { get; set; }

        // 新增Cookie容器,保存认证Cookie
        private CookieContainer _cookieContainer = new CookieContainer();

        public RestClient ( ) {
            endPoint = string.Empty;
            httpMethod = httpVerb.GET;
        }

        public string makeRequest(bool isLoginRequest = false) {
            string strResponseValue = string.Empty;
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
            request.Method = httpMethod.ToString();
            request.CookieContainer = _cookieContainer;

            if (isLoginRequest) {
                // 构造登录表单数据,字段名需与站点Login.aspx实际字段一致
                string postData = $"UserName={Uri.EscapeDataString(userName)}&Password={Uri.EscapeDataString(userPassword)}&RememberMe=false";
                byte[] data = System.Text.Encoding.UTF8.GetBytes(postData);
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = data.Length;
                using (Stream stream = request.GetRequestStream()) {
                    stream.Write(data, 0, data.Length);
                }
            }

            HttpWebResponse response = null;
            try {
                response = (HttpWebResponse)request.GetResponse();
                // 保存响应中的Cookie到容器
                _cookieContainer.Add(response.Cookies);

                using (Stream responseStream = response.GetResponseStream()) {
                    if (responseStream != null) {
                        using (StreamReader reader = new StreamReader(responseStream)) {
                            strResponseValue = reader.ReadToEnd();
                        }
                    }
                }
            }
            catch (Exception ex) {
                strResponseValue = "{\"errorMessages\":[\"" + ex.Message.ToString() + "\"],\"errors\":{}}";
            }
            finally {
                response?.Dispose();
            }
            return strResponseValue;
        }
    }
}

调整调用流程,先登录获取Cookie再调用Handler:

private void LoadStats() {
    RestClient rClient = new RestClient();
    // 第一步:发送登录请求获取认证Cookie
    rClient.endPoint = "https://[my site URL].com/Login.aspx";
    rClient.httpMethod = httpVerb.POST;
    rClient.userName = "<username>";
    rClient.userPassword = "<password>";
    rClient.makeRequest(isLoginRequest: true);

    // 第二步:携带Cookie调用Handler
    rClient.endPoint = "https://[my site URL].com/handlers/gettodaystats.ashx";
    rClient.httpMethod = httpVerb.GET;
    string strResponse = rClient.makeRequest();
    MessageBox.Show(strResponse);
}

注意:登录表单的字段名需与站点Login.aspx页面的实际字段ID一致(可通过查看登录页源码确认,可能是类似ctl00$MainContent$UserName的ASP.NET生成ID)。


内容的提问来源于stack exchange,提问作者RiverNet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:04:52