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

ASP.NET WebForms借助itfoxtec-identity-saml2实现用户名密码验证SSO方案咨询

向IdP传递的核心SAML请求参数
  • Issuer(SP实体ID):当前WebForms应用作为服务提供商的唯一标识,必须和IdP侧预先配置的SP实体ID完全一致
  • ACS(断言消费服务)地址:IdP完成身份认证后回传SAML响应的回调地址,需和IdP侧配置的SP回调地址匹配
  • RelayState:非强制但建议携带,用来存储认证成功后要跳转的应用主页面路径,避免认证完成后跳转地址丢失
  • NameIDPolicy:指定IdP返回的用户标识格式,按需配置为持久化、临时或邮箱等格式
  • 请求签名:如果IdP要求请求防篡改,需要附带SP私钥签名后的请求内容
ASP.NET WebForms 集成实现步骤
  1. 安装依赖包:通过NuGet安装对应.NET Framework版本的itfoxtec.identity.saml2组件,.NET Framework 4.6.1及以上版本均支持
  2. 配置参数:将IdP和SP的相关配置项存入web.config,避免硬编码方便后续修改
  3. 改造现有登录页:移除原有本地账号密码验证逻辑,用户点击登录按钮后直接构造SAML认证请求,重定向到IdP的SSO端点
  4. 新增回调处理页:专门用来接收IdP返回的SAML响应,完成响应验签、身份解析后创建本地登录会话,再跳转至应用主页面
  5. IdP侧配置:将每套WebForms应用的SP实体ID、ACS地址、签名证书等信息注册到IdP,确保两边配置完全匹配
核心代码示例

web.config配置

<configuration>
  <appSettings>
    <!-- IdP侧配置 -->
    <add key="Saml2:IdPEntityId" value="IdP提供的实体ID" />
    <add key="Saml2:IdPSSOUrl" value="IdP的SSO登录端点地址" />
    <add key="Saml2:IdPSignCertThumbprint" value="IdP签名证书的SHA1指纹,空格可忽略" />
    <!-- 当前应用(SP)配置 -->
    <add key="Saml2:SPEntityId" value="当前应用的唯一标识,比如https://yourappdomain.com" />
    <add key="Saml2:SPACSUrl" value="https://yourappdomain.com/AcsCallback.aspx" />
    <add key="Saml2:DefaultMainPage" value="~/Main.aspx" />
  </appSettings>
  <system.web>
    <authentication mode="Forms" />
  </system.web>
</configuration>

登录页(Login.aspx.cs)登录按钮逻辑

using System;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using ITfoxtec.Identity.Saml2;
using ITfoxtec.Identity.Saml2.Bindings;
using ITfoxtec.Identity.Saml2.Request;

public partial class Login : System.Web.UI.Page
{
    protected void btnLogin_Click(object sender, EventArgs e)
    {
        var samlConfig = new Saml2Configuration
        {
            Issuer = ConfigurationManager.AppSettings["Saml2:SPEntityId"],
            SingleSignOnDestination = new Uri(ConfigurationManager.AppSettings["Saml2:IdPSSOUrl"]),
            AllowedIssuer = ConfigurationManager.AppSettings["Saml2:IdPEntityId"]
        };
        // 加载IdP签名证书用于后续响应验签
        samlConfig.SignatureValidationCertificates.Add(LoadCertificate(ConfigurationManager.AppSettings["Saml2:IdPSignCertThumbprint"]));

        // 构造SAML认证请求
        var authnRequest = new Saml2AuthnRequest(samlConfig);
        var redirectBinding = new Saml2RedirectBinding();
        // 绑定跳转地址,认证完成后回到应用主页面
        redirectBinding.Bind(authnRequest, HttpUtility.UrlEncode(ConfigurationManager.AppSettings["Saml2:DefaultMainPage"])).ApplyToResponse(Response);
        Response.End();
    }

    // 从本地证书存储加载证书的辅助方法,也可调整为读取证书文件
    private X509Certificate2 LoadCertificate(string thumbprint)
    {
        thumbprint = thumbprint.Replace(" ", "").ToUpperInvariant();
        using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        {
            store.Open(OpenFlags.ReadOnly);
            var certs = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, validOnly: false);
            if (certs.Count == 0) throw new Exception("未找到指定指纹的证书");
            return certs[0];
        }
    }
}

回调页(AcsCallback.aspx.cs)处理逻辑

using System;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using System.Web.Security;
using ITfoxtec.Identity.Saml2;
using ITfoxtec.Identity.Saml2.Bindings;
using ITfoxtec.Identity.Saml2.Response;

public partial class AcsCallback : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        var samlConfig = new Saml2Configuration
        {
            Issuer = ConfigurationManager.AppSettings["Saml2:SPEntityId"],
            AllowedIssuer = ConfigurationManager.AppSettings["Saml2:IdPEntityId"]
        };
        samlConfig.SignatureValidationCertificates.Add(LoadCertificate(ConfigurationManager.AppSettings["Saml2:IdPSignCertThumbprint"]));

        // 读取IdP回传的SAML响应
        var postBinding = new Saml2PostBinding();
        var authResponse = new Saml2AuthnResponse(samlConfig);
        postBinding.ReadSamlResponse(Request.ToGenericHttpRequest(), authResponse);

        // 验证响应状态
        if (authResponse.Status != Saml2StatusCodes.Success)
        {
            Response.Write($"认证失败:{authResponse.Status}");
            Response.End();
        }

        // 认证通过,创建本地登录会话
        var loginUser = authResponse.ClaimsPrincipal.Identity.Name;
        FormsAuthentication.SetAuthCookie(loginUser, false);

        // 跳转到登录前指定的页面
        var redirectUrl = HttpUtility.UrlDecode(postBinding.RelayState) ?? ConfigurationManager.AppSettings["Saml2:DefaultMainPage"];
        Response.Redirect(redirectUrl);
    }

    // 同登录页的证书加载方法,也可以抽成公共方法复用
    private X509Certificate2 LoadCertificate(string thumbprint)
    {
        thumbprint = thumbprint.Replace(" ", "").ToUpperInvariant();
        using (var store = new X509Store(StoreName.My, StoreLocation.LocalMachine))
        {
            store.Open(OpenFlags.ReadOnly);
            var certs = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, validOnly: false);
            if (certs.Count == 0) throw new Exception("未找到指定指纹的证书");
            return certs[0];
        }
    }
}
注意事项
  • 若IdP要求SAML请求必须签名,需要给Saml2Configuration的SigningCertificate属性配置SP的签名证书
  • IIS应用池运行身份需要有证书存储的读取权限,否则会出现证书加载失败的问题
  • 多套WebForms应用各自配置独立的SP实体ID和ACS地址,分别在IdP侧注册即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:09:02