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

如何在.NET Core 6中基于Duende IdentityServer4结合ADFS SAML实现SSO

整体对接逻辑

现有架构无需做底层重构,完整SSO链路为:用户访问.NET 6 Core API/关联业务客户端 → 跳转至已部署的Duende IdentityServer 4 → IdentityServer作为SAML服务提供方(SP)将认证请求转发给作为SAML身份提供方(IdP)的ADFS → ADFS完成域内账号校验后回传SAML断言 → IdentityServer校验断言合法后,按原有OIDC协议签发访问令牌给API/客户端。已经对接好IdentityServer的业务API完全不用修改原有OIDC鉴权逻辑,所有SAML适配动作都在IdentityServer侧完成即可。

前置准备项
  • 现有Duende IdentityServer 4实例运行正常,已配置的OIDC客户端、API资源校验通过,运行时为.NET 6
  • 拥有ADFS服务器管理权限,可配置信赖方信任、导出IdP元数据
  • 现有.NET 6 Core API已完成JWT Bearer鉴权对接,可正常校验IdentityServer签发的访问令牌
分步落地步骤

第一步:IdentityServer侧集成SAML协议支持

Duende IdentityServer核心框架原生不带SAML SP能力,直接安装官方配套的SAML2P协议插件NuGet包即可,包版本和当前使用的Duende IdentityServer 4主版本保持一致,避免版本兼容问题。
安装完成后在Program.cs中注册SAML插件,原有IdentityServer配置保持不变:

builder.Services.AddIdentityServer()
    // 原有配置(AddSigningCredential、AddInMemoryClients/AddConfigurationStore等)保留不动
    .AddSaml2pPlugin(options =>
    {
        // 配置和当前Duende许可匹配的SAML插件许可,符合社区版配额要求可直接使用社区许可
        options.LicenseKey = "你的Duende SAML组件许可";
    });

第二步:添加ADFS为SAML外部身份提供商

  1. 先从ADFS服务器导出IdP元数据,默认元数据路径为ADFS服务地址下的/FederationMetadata/2007-06/FederationMetadata.xml,将元数据XML文件存放到IdentityServer项目的Config目录下做本地缓存,避免每次启动远程拉取元数据被防火墙拦截。
  2. 在Program.cs中添加SAML认证方案,对接ADFS:
builder.Services.AddAuthentication()
    .AddSaml2p("adfs-saml", "ADFS域账号登录", options =>
    {
        // 加载本地缓存的ADFS IdP元数据
        options.IdPMetadata = File.ReadAllText(Path.Combine(builder.Environment.ContentRootPath, "Config", "adfs-metadata.xml"));
        // 配置SP实体ID,必须和后续ADFS侧配置的信赖方标识完全一致,格式参考:https://你的IdentityServer域名/saml2/sp
        options.SPEntityId = "https://ids.your-domain.com/saml2/sp";
        // 签名算法和ADFS侧保持一致,统一用RsaSha256即可
        options.SignatureAlgorithm = Microsoft.IdentityModel.Tokens.SecurityAlgorithms.RsaSha256Signature;
        // 声明映射,把ADFS返回的域账号属性映射为IdentityServer标准声明
        options.ClaimActions.MapUniqueClaim(System.Security.Claims.ClaimTypes.NameIdentifier, "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname");
        options.ClaimActions.MapUniqueClaim(System.Security.Claims.ClaimTypes.Email, System.Security.Claims.ClaimTypes.Email);
        options.ClaimActions.MapUniqueClaim(System.Security.Claims.ClaimTypes.Name, System.Security.Claims.ClaimTypes.Name);
        // 强制要求ADFS对返回的断言签名,避免断言篡改
        options.RequireIdPSignedAssertions = true;
    });

在IdentityServer的登录页配置中,把adfs-saml方案作为登录选项展示即可,用户点击后会自动跳转到ADFS登录页。

第三步:ADFS侧配置信赖方信任

登录ADFS服务器打开ADFS管理控制台,按以下步骤配置:

  • 选择「新增信赖方信任」,选择「从在线或本地文件导入信赖方元数据」,元数据地址为IdentityServer的SAML SP元数据地址,格式为https://你的IdentityServer域名/saml2/sp/metadata,导入后系统会自动补全SP的回调地址、签名证书等参数,无需手动填写
  • 配置访问控制策略,根据业务需求选择允许登录的域用户组,一般选择允许指定业务部门用户组或所有域用户
  • 新增声明颁发规则,选择「发送LDAP属性为声明」模板,属性存储选择Active Directory,做以下映射:
    • 传出声明类型选「名称标识符」,映射到LDAP属性SAM-Account-Name
    • 传出声明类型选「电子邮件地址」,映射到LDAP属性E-Mail-Addresses
    • 传出声明类型选「名称」,映射到LDAP属性Display-Name
  • 保存信赖方信任配置后,打开信赖方属性页,找到「高级」选项卡,把签名哈希算法改为SHA-256,和IdentityServer侧配置保持一致,避免老版本ADFS默认用SHA-1导致签名校验失败。

第四步:配置IdentityServer外部登录回调逻辑

这部分和普通OIDC外部登录的处理逻辑完全一致,不需要针对SAML做特殊开发:

  • 在外部登录回调Action中,拿到ADFS返回的用户声明后,根据域账号做本地用户关联:如果有本地用户库,就用返回的NameIdentifier(也就是域账号)匹配本地用户;如果不需要本地账号映射,可以动态创建临时用户记录
  • 构造IdentityServer登录上下文后,调用原生HttpContext.SignInAsync方法签发本地认证Cookie,再按框架默认逻辑跳转回客户端/API的授权回调地址即可。
  • 如果需要把域账号相关声明下发给API,记得在IdentityServer的ApiScope配置中,把对应声明加入访问令牌的声明列表,否则声明不会被写入access token。

第五步:.NET 6 Core API侧适配

这部分几乎不需要修改代码:

  • 确认API现有的JWT Bearer校验逻辑正常,只要是IdentityServer签发的合法令牌即可通过校验,不需要额外加SAML相关的处理逻辑
  • 业务接口需要用到用户域账号、邮箱等信息时,直接从User.Claims中读取对应声明即可。
常见排错点
  • 重定向到ADFS时报元数据解析错误:检查本地缓存的ADFS元数据文件是否完整、XML格式是否损坏,确认IdentityServer服务器可以正常访问ADFS服务地址
  • ADFS回跳IdentityServer时报签名校验失败:检查两边签名算法是否一致、SP实体ID是否完全匹配、IdentityServer的签名证书是否在有效期内
  • 回跳后拿不到用户声明:检查ADFS侧的声明颁发规则是否正确配置、映射的LDAP属性是否对应用户有值,确认IdentityServer侧的声明映射规则写法正确
  • API侧拿不到域账号相关声明:检查IdentityServer中对应ApiScope的声明配置,确认需要的声明已经加入访问令牌的下发列表。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:27:22