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 集成实现步骤
- 安装依赖包:通过NuGet安装对应.NET Framework版本的
itfoxtec.identity.saml2组件,.NET Framework 4.6.1及以上版本均支持 - 配置参数:将IdP和SP的相关配置项存入web.config,避免硬编码方便后续修改
- 改造现有登录页:移除原有本地账号密码验证逻辑,用户点击登录按钮后直接构造SAML认证请求,重定向到IdP的SSO端点
- 新增回调处理页:专门用来接收IdP返回的SAML响应,完成响应验签、身份解析后创建本地登录会话,再跳转至应用主页面
- 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
相关产品推荐
相关产品推荐

