自定义 SAML 令牌声明
Microsoft 标识平台支持在应用程序库中的大多数预集成应用程序和自定义应用程序上进行单一登录 (SSO)。 当用户使用 SAML 2.0 协议通过 Microsoft 标识平台向应用程序进行身份验证时,系统会将令牌发送到该应用程序。 应用程序验证并使用令牌使用户登录,而不是提示输入用户名和密码。
这些 SAML 令牌包含有关用户已知的“声明”的信息片段。 “声明”是标识提供者在为某个用户颁发的令牌中陈述的有关该用户的信息。 在 SAML 令牌中,声明数据通常包含在 SAML 属性语句中。 用户的唯一 ID 通常在 SAML 主题中表示,也称为名称标识符 (nameID
)。
默认情况下,Microsoft 标识平台会向应用程序颁发一个包含声明的 SAML 令牌,该声明的值为用户的用户名(也称为用户主体名称),可以唯一标识该用户。 SAML 令牌还含有其他声明,其中包含用户的电子邮件地址、名字和姓氏。
查看或编辑声明
要查看或编辑 SAML 令牌中颁发给应用程序的声明,请执行以下操作:
- 至少以云应用程序管理员身份登录到 Microsoft Entra 管理中心。
- 浏览到“标识”>“应用程序”>“企业应用程序”>“所有应用程序”。
- 选择应用程序,在左侧菜单中选择“单一登录”,然后在“属性和声明”部分中选择“编辑”。
以下原因可能导致需要编辑 SAML 令牌中颁发的声明:
- 应用程序要求
NameIdentifier
声明或nameID
声明不是用户名(或用户主体名称)。 - 应用程序已编写为需要一组不同的声明 URI 或声明值。
编辑 nameID
若要编辑名称标识符值声明,请执行以下操作:
- 打开“名称标识符值”页面。
- 选择属性或要应用于属性的转换。 也可以指定希望
nameID
声明具有的格式。
NameID 格式
如果 SAML 请求中包含具有特定格式的元素 NameIDPolicy
,则 Microsoft 标识平台会接受请求中的格式。
如果 SAML 请求中不包含用于 NameIDPolicy
的元素,则 Microsoft 标识平台会使用你指定的格式来颁发 nameID
。 如果未指定格式,Microsoft 标识平台会使用与所选声明源关联的默认源格式。 如果转换导致 null 值或非法值,Microsoft Entra ID 会在 nameID
中发送一个持久的成对标识符。
从“选择名称标识符格式”下拉列表中,选择下表中的选项之一。
nameID 格式 |
说明 |
---|---|
Default | Microsoft 标识平台使用默认的源格式。 |
Persistent | Microsoft 标识平台使用 Persistent 作为 nameID 格式。 |
电子邮件地址 | Microsoft 标识平台使用 EmailAddress 作为 nameID 格式。 |
Unspecified | Microsoft 标识平台使用 Unspecified 作为 nameID 格式。 |
Windows 域限定名 | Microsoft 标识平台使用 WindowsDomainQualifiedName 格式。 |
还支持临时 nameID
,但在下拉列表中不可用,并且不能在 Azure 端进行配置。 若要了解有关 NameIDPolicy
属性的详细信息,请参阅单一登录 SAML 协议。
属性
提示
本文中的步骤可能因开始使用的门户而略有不同。
为 NameIdentifier
(或 nameID
)声明选择所需的源。 可从下表中的选项中进行选择。
名称 | 说明 |
---|---|
Email |
用户的电子邮件地址。 |
userprincipalName |
用户的用户主体名称 (UPN)。 |
onpremisessamaccountname |
已从本地 Microsoft Entra ID 同步的 SAM 帐户名。 |
objectid |
Microsoft Entra ID 中的用户的对象 ID。 |
employeeid |
用户的员工 ID。 |
Directory extensions |
目录扩展使用 Microsoft Entra Connect Sync 从本地 Active Directory 同步。 |
Extension Attributes 1-15 |
用于扩展 Microsoft Entra 架构的本地扩展属性。 |
pairwiseid |
用户标识符的持久形式。 |
有关标识符值的详细信息,请参阅本页后面列出每个源的有效 ID 值的表。
任何常量(静态)值都可以分配给任何声明。 使用以下步骤分配常量值:
- 在“属性和声明”边栏选项卡上,选择要修改的必需声明。
- 在“源属性”中按组织输入不带引号的常量值,然后选择“保存”。 将显示常数值。
目录架构扩展
还可以将目录架构扩展属性配置为非条件/条件属性。 使用以下步骤将单值或多值目录架构扩展属性配置为声明:
- 在“属性和声明”边栏选项卡上,选择“添加新声明”或编辑现有声明。
- 从定义扩展属性的应用选择器中选择源应用。
- 选择“添加”将选择添加到声明中。
- 单击“保存”以提交更改。
特定声明转换
可以使用以下特殊声明转换函数。
函数 | 说明 |
---|---|
ExtractMailPrefix() | 删除电子邮件地址或用户主体名称中的域后缀。 此功能只会提取传递用户名的第一部分(例如,“joe_smith”而不是 joe_smith@contoso.com)。 |
ToLower() | 将所选属性的字符转换为小写字符。 |
ToUpper() | 将所选属性的字符转换为大写字符。 |
添加特定于应用程序的声明
要添加特定于应用程序的声明:
- 在“属性和声明”边栏选项卡上,选择“添加新声明”以打开“管理用户声明”页。
- 输入声明的“名称”。 根据 SAML 规范,此值无需严格遵循 URI 模式。如果需要 URI 模式,可以将其放入命名空间字段。
- 选择声明可检索其值的源。 可以从“源属性”下拉列表中选择一个用户属性,或者在用户属性作为声明发出之前对其应用转换。
添加组声明
组声明用于做出授权决策,以便由应用或服务提供商访问资源。 若要添加组声明,请采取以下操作;
- 导航到“应用注册”,选择要向其添加组声明的应用。
- 选择“添加组声明”。
- 选择要包含在令牌中的组类型。 可以添加分配给特定应用程序的安全组、目录组或组。
- 选择要包含在组声明中的值,然后选择“添加”。
声明转换
对用户属性应用转换:
- 在管理声明中,选择转换作为声明源,以打开管理转换页。
- 从“转换”下拉列表中选择函数。 根据选择的函数,提供参数和常量值以在转换中进行计算。
- 单击相应的单选按钮,选择属性的源。
- 从下拉列表中选择属性名称。
- “将源视为多值”是一个复选框,指示转换是应用于所有值还是仅应用于第一个值。 默认情况下,转换将仅应用于多值声明中的第一个元素,选中此复选框可确保它应用于所有元素。 此复选框将仅对多值属性启用,例如
user.proxyaddresses
。 - 若要应用多个转换,请选择“添加转换”。 对一个声明最多可以应用两个转换。 例如,可以先提取
user.mail
的电子邮件前缀。 然后,将字符串设为大写。
可以使用以下功能转换声明。
函数 | 说明 |
---|---|
ExtractMailPrefix() | 删除电子邮件地址或用户主体名称中的域后缀。 此功能只会提取传递用户名的第一部分。 例如,joe_smith ,而非 joe_smith@contoso.com 。 |
Join() | 通过联接两个属性来创建新的值。 或者,可以在两个属性之间使用分隔符。 对于 nameID 声明转换,在转换输入具有域部分时,Join() 函数具有特定行为。 它会先从输入中删除域部分,然后再将输入与分隔符和所选参数联接起来。 例如,如果转换的输入为 joe_smith@contoso.com ,分隔符为 @ ,参数为 fabrikam.com ,则此输入组合最终会生成 joe_smith@fabrikam.com 。 |
ToLowercase() | 将所选属性的字符转换为小写字符。 |
ToUppercase() | 将所选属性的字符转换为大写字符。 |
Contains() | 如果输入与指定的值匹配,则输出一个属性或常量。 否则,如果没有匹配项,则可以指定其他输出。 例如,如果想要发出一个声明,其中的值为用户的电子邮件地址(如果包含域 @contoso.com ),否则就需要输出用户主体名称。 若要执行此函数,请配置以下值:Parameter 1(input): user.email 、Value: "@contoso.com" 、Parameter 2 (output): user.email 和 Parameter 3 (output if there's no match): user.userprincipalname 。 |
EndWith() | 如果输入以指定值结束,则输出一个属性或常量。 否则,如果没有匹配项,则可以指定其他输出。 例如,如果想要发出一个声明,其中的值为用户的员工 ID (如果员工 ID 以 000 结束),否则就需要输出一个扩展属性。 若要执行此函数,请配置以下值:Parameter 1(input): user.employeeid 、Value: "000" 、Parameter 2 (output): user.employeeid 和 Parameter 3 (output if there's no match): user.extensionattribute1 。 |
StartWith() | 如果输入以指定值开始,则输出一个属性或常量。 否则,如果没有匹配项,则可以指定其他输出。 例如,如果想要发出一个声明,其中的值为用户的员工 ID(如果国家/地区以“US ”开始),否则就需要输出一个扩展属性。 若要执行此函数,请配置以下值:Parameter 1(input): user.country 、Value: "US" 、Parameter 2 (output): user.employeeid 和 Parameter 3 (output if there's no match): user.extensionattribute1 |
Extract() - 匹配后 | 匹配指定值后返回的子字符串。 例如,如果输入的值为 Finance_BSimon ,匹配值为 Finance_ ,则声明的输出为 BSimon 。 |
Extract() - 匹配前 | 在匹配指定值前返回的子字符串。 例如,如果输入的值为 BSimon_US ,匹配值为 _US ,则声明的输出为 BSimon 。 |
Extract() - 匹配之间 | 在匹配指定值前返回的子字符串。 例如,如果输入的值为 Finance_BSimon_US ,第一个匹配值为 Finance_ ,第二个匹配值为 _US ,则声明的输出为 BSimon 。 |
ExtractAlpha() - 前缀 | 返回字符串的前缀字母部分。 例如,如果输入的值为 BSimon_123 ,则它将返回 BSimon 。 |
ExtractAlpha() - 后缀 | 返回字符串的后缀字母部分。 例如,如果输入的值为 123_Simon ,则它将返回 Simon 。 |
ExtractNumeric() - 前缀 | 返回字符串的前缀数字部分。 例如,如果输入的值为 123_BSimon ,则它将返回 123 。 |
ExtractNumeric() - 后缀 | 返回字符串的后缀数字部分。 例如,如果输入的值为 BSimon_123 ,则它将返回 123 。 |
IfEmpty() | 如果输入为 null 或为空,则输出一个属性或常量。 例如,如果希望在用户的员工 ID 为空时输出存储在扩展属性中的属性。 若要执行此函数,请配置以下值:Parameter 1(input): user.employeeid 、Parameter 2 (output): user.extensionattribute1 和 Parameter 3 (output if there's no match): user.employeeid 。 |
IfNotEmpty() | 如果输入不为 null 或空,则输出一个属性或常量。 例如,如果希望在用户的员工 ID 不为空时输出存储在扩展属性中的属性。 若要执行此函数,请配置以下值:Parameter 1(input): user.employeeid 和 Parameter 2 (output): user.extensionattribute1 。 |
Substring() - 固定长度 | 提取字符串声明类型的组成部分(从位于指定位置处的字符开始),并返回指定数目的字符。 sourceClaim 是应执行的转换的声明源。 StartIndex 是此实例中子字符串的起始字符位置(从零开始)。 Length 是子字符串的字符长度。 例如,sourceClaim - PleaseExtractThisNow 、StartIndex - 6 和 Length - 11 将生成 ExtractThis 的输出。 |
Substring() - EndOfString | 从指定位置的字符开始,提取字符串声明类型的部分内容,并返回声明中从指定起始索引开始的剩余内容。 sourceClaim 是应执行的转换的声明源。 StartIndex 是此实例中子字符串的起始字符位置(从零开始)。 例如,sourceClaim - PleaseExtractThisNow 和 StartIndex - 6 生成 ExtractThisNow 的输出。 |
RegexReplace() | 有关基于正则表达式的声明转换的详细信息,请参阅下一部分。 |
基于正则表达式的声明转换
下图显示了第一级转换的示例:
下表中列出的操作提供有关第一级转换的信息,并对应于上图中的标签。 选择“编辑”以打开声明转换边栏选项卡。
操作 | 字段 | 说明 |
---|---|---|
1 |
Transformation |
从“转换”选项中选择“RegexReplace()”选项以使用基于正则表达式的声明转换方法进行声明转换。 |
2 |
Parameter 1 |
正则表达式转换的输入。 例如,具有用户电子邮件地址(如 admin@fabrikam.com )的 user.mail。 |
3 |
Treat source as multivalued |
某些输入用户属性可以是多值用户属性。 如果所选用户属性支持多个值,并且用户希望对转换使用多个值,则需要选中“将源视为多值”。 如果选中,则所有值都用于正则表达式匹配,否则仅使用第一个值。 |
4 |
Regex pattern |
一个正则表达式,根据选为“参数 1”的用户属性的值计算。 例如,从用户的电子邮件地址中提取用户别名的正则表达式将表示为 (?'domain'^.*?)(?i)(\@fabrikam\.com)$ 。 |
5 |
Add additional parameter |
多个用户属性可用于转换。 然后,属性的值将与正则表达式转换输出合并。 最多支持另外五个参数。 |
6 |
Replacement pattern |
替换模式是文本模板,其中包含正则表达式结果的占位符。 所有组名称都必须包在大括号内,例如 {group-name} 。 比方说,管理部门想要将用户别名与其他域名(例如 xyz.com )一起使用,并将国家/地区名称与其合并。 在这种情况下,替换模式将是 {country}.{domain}@xyz.com ,其中 {country} 是输入参数的值,而 {domain} 是正则表达式计算的组输出。 在这种情况下,预期结果为 US.swmal@xyz.com 。 |
下图显示了第二级转换的示例:
下表提供了有关第二级转换的信息。 表中列出的操作对应于上图中的标签。
操作 | 字段 | 说明 |
---|---|---|
1 |
Transformation |
基于正则表达式的声明转换不限于第一级转换,还可以用作第二级转换。 任何其他转换方法都可以用作第一级转换。 |
2 |
Parameter 1 |
如果选择 RegexReplace() 作为第二级转换,则第一级转换的输出将用作二级转换的输入。 要应用转换,第二级正则表达式应与第一级转换的输出匹配。 |
3 |
Regex pattern |
“正则表达式模式”是第二级转换的正则表达式。 |
4 |
Parameter input |
第二级转换的用户属性输入。 |
5 |
Parameter input |
如果管理员不再需要所选输入参数,则可以将其删除。 |
6 |
Replacement pattern |
替换模式是文本模板,其中包含正则表达式结果组名称、输入参数组名称和静态文本值的占位符。 所有组名称都必须包在大括号内,例如 {group-name} 。 比方说,管理部门想要将用户别名与其他域名(例如 xyz.com )一起使用,并将国家/地区名称与其合并。 在这种情况下,替换模式将是 {country}.{domain}@xyz.com ,其中 {country} 是输入参数的值,而 {domain} 是正则表达式计算的组输出。 在这种情况下,预期结果为 US.swmal@xyz.com 。 |
7 |
Test transformation |
仅当“参数 1”的选定用户属性的值与“正则表达式模式”文本框中提供的正则表达式匹配时,才会计算 RegexReplace() 转换。 如果它们不匹配,则默认声明值将添加到令牌中。 为了根据输入参数值验证正则表达式,可以在转换边栏选项卡中选择测试体验。 此测试体验仅对虚拟值进行操作。 如果使用更多的输入参数,参数的名称将添加到测试结果而不是实际值。 若要访问测试部分,请选择“测试转换”。 |
下图显示了测试转换的示例:
下表提供了有关转换的信息。 表中列出的操作对应于上图中的标签。
操作 | 字段 | 说明 |
---|---|---|
1 |
Test transformation |
选择关闭或 (X) 按钮将隐藏测试部分,并在边栏选项卡上再次重新呈现“测试转换”按钮。 |
2 |
Test regex input |
接受用于正则表达式测试计算的输入。 如果将基于正则表达式的声明转换配置为第二级转换,将会提供属于第一级转换预期输出的一个值。 |
3 |
Run test |
提供测试正则表达式输入并配置“正则表达式模式”、“替换模式”和“输入参数”后,可以通过选择“运行测试”来计算表达式。 |
4 |
Test transformation result |
如果计算成功,将会根据“测试转换结果”标签呈现测试转换的输出。 |
5 |
Remove transformation |
可以通过选择“删除转换”来删除第二级转换。 |
6 |
Specify output if no match |
如果针对“参数 1”配置的正则表达式输入值与“正则表达式”不匹配,则跳过转换。 在这种情况下,可以配置备用用户属性,通过选中“指定在没有匹配项的情况下的输出”即可将其添加到声明的令牌中。 |
7 |
Parameter 3 |
如果在没有匹配项时需要返回备用用户属性,并且如果未选中“指定在没有匹配项的情况下的输出”,可以使用下拉列表选择备用用户属性。 此下拉列表对应于“参数 3(不匹配时输出)”。 |
8 |
Summary |
在边栏选项卡底部,显示了格式的完整摘要,其中以简单的文本解释了转换的含义。 |
9 |
Add |
验证转换的配置设置后,可以通过选择“添加”将其保存到声明策略。 在管理声明边栏选项卡上选择保存以保存更改。 |
RegexReplace() 转换也可用于组声明转换。
RegexReplace () 转换验证
选择“添加”或“运行”测试后出现以下情况时,将显示一条消息,提供有关问题的详细信息:
- 不允许具有重复用户属性的输入参数。
- 找到了未使用的输入参数。 定义的输入参数在替换模式文本中应具有相应的用法。
- 提供的测试正则表达式输入与提供的正则表达式不匹配。
- 找不到替换模式中组的源。
将 UPN 声明添加到 SAML 令牌
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn
声明是 SAML 受限制声明集的一部分。 如果配置了自定义签名密钥,则可以将其添加到“属性和声明”部分。
如果未配置自定义签名密钥,请参阅 SAML 受限制声明集。 可以通过 Azure 门户中的“应用注册”将其添加为可选声明。
在“应用注册”中打开应用程序,选择“令牌配置”,然后选择“添加可选声明”。 选择 SAML 令牌类型,从列表中选择 upn,然后单击“添加”将声明添加到令牌。
在“属性和声明”部分中完成的自定义可以覆盖“应用注册”中的可选声明。
发出基于条件的声明
能够根据用户类型和用户所属的组来指定声明的源。
用户类型可以是:
- 任何 - 允许所有用户访问应用程序。
- 成员:本机租户的成员
- 所有来宾:用户来自具有或没有 Microsoft Entra ID 的外部组织。
- Microsoft Entra 来宾:来宾用户属于使用 Microsoft Entra ID 的另一个组织。
- 外部来宾:来宾用户属于没有 Microsoft Entra ID 的外部组织。
用户类型在以下场景中很有用:来宾和员工访问应用程序使用的声明源不同。 可做如下规定:如果用户是员工,则 NameID 来自 user.email。 如果用户是来宾,则 NameID 来自 user.extensionattribute1。
要添加声明条件:
- 在管理声明中,展开”声明条件”。
- 选择用户类型。
- 选择用户所属的组。 在某个给定应用程序的所有声明中,最多可以选择 50 个独一无二的组。
- 选择声明可检索其值的源。 可以从源属性下拉列表中选择一个用户属性,或者对用户属性应用转换。 在用户属性作为声明发出之前,还可以选择目录架构扩展。
添加条件的顺序很重要。 Microsoft Entra 首先使用源 Attribute
评估所有条件,然后使用源 Transformation
评估所有条件,以确定要在声明中发出哪个值。 从上到下评估具有相同源的条件。 与表达式匹配的最后一个值将在声明中发出。 转换(如 IsNotEmpty
和 Contains
)的作用类似于限制。
例如,Britta Simon 是 Contoso 租户中的来宾用户。 Britta 属于另一个也使用 Microsoft Entra ID 的组织。 基于以下对 Fabrikam 应用程序的配置,如果 Britta 尝试登录到 Fabrikam,Microsoft 标识平台将评估条件。
首先,Microsoft 标识平台会验证 Britta 的用户类型是否为“所有来宾”。 由于类型为“所有来宾”,因此 Microsoft 标识平台会将声明的源分配到 user.extensionattribute1
。 其次,Microsoft 标识平台会验证 Britta 的用户类型是否为“Microsoft Entra 来宾”。 由于类型为“所有来宾”,因此 Microsoft 标识平台会将声明的源分配到 user.mail
。 最后,使用值 user.mail
为 Britta 发出声明。
作为另一个示例,请考虑当 Britta Simon 尝试登录时,使用以下配置会发生什么情况。 首先使用 Attribute
的源评估所有条件。 因为 Britta 的用户类型为“AAD 来宾”,所以将 user.mail
分配为声明的源。 接下来,计算转换。 由于 Britta 是来宾,因此 user.extensionattribute1
现在是声明的新源。 由于 Britta 是 Microsoft Entra 来宾,因此 user.othermail
现在是声明的源。 最后,使用值 user.othermail
为 Britta 发出声明。
作为最后一个示例,请考虑如果 Britta 未配置 user.othermail
或其为空,会发生什么情况。 在这两种情况下,都将忽略条件项,而声明将回退到 user.extensionattribute1
。
高级 SAML 声明选项
可以为 SAML2.0 应用程序配置高级声明选项,以公开与 OIDC 令牌相同的声明,对于打算对 SAML2.0 和 OIDC 响应令牌使用相同的声明的应用程序,亦是如此。
可以通过选中“管理声明”边栏选项卡中的“高级 SAML 声明选项”下的框来配置高级声明选项。
下表列出了可为应用程序配置的其他高级选项。
选项 | 说明 |
---|---|
将应用程序 ID 追加到颁发者 | 自动将应用程序 ID 添加到颁发者声明。 如果同一个应用程序有多个的实例,则此选项可确保每个实例的唯一声明值。 如果没有为应用程序配置自定义签名密钥,则忽略此设置。 |
替代受众声明 | 允许覆盖发送到应用程序的受众声明。 提供的值必须为有效的绝对 URI。 如果没有为应用程序配置自定义签名密钥,则忽略此设置。 |
包括属性名称格式 | 如果选中,Microsoft Entra ID 会添加一个名为 NameFormat 的属性,用于描述应用程序的受限、核心和可选声明的名称格式。 有关详细信息,请查看声明映射策略类型 |