使用 Azure AD B2C 自定义身份提供程序 (OpenID Connect) 映射声明
Mapping claims with Azure AD B2C Custom Identity Provider (OpenID Connect)
尽管我已经很好地设置了所有声明映射,因此它们与我们的 Identity Server 3 发布的匹配,但我们在 Azure AD 端似乎没有这些值。姓名和电子邮件是可以用作示例的声明。奇怪的是,这只发生在自定义身份提供者 (Open ID Connect) 中,而例如 Facebook 内置的身份提供者运行良好,并接受从 IdP 收到的声明。有没有人做过这项工作?
[编辑]
此外,我还尝试通过此处建议的自定义策略来实现此目的:。现在,我面临着另一个问题,即使用自定义策略将 AAD B2C 简单地连接到 Identity Server 3。这是我来自 TrustFrameworkExnsion.xml:
的 TechnicalProfile 定义
<TechnicalProfile Id="IdentityServerProfile">
<DisplayName>IdentityServer</DisplayName>
<Description>Login with your IdentityServer account</Description>
<Protocol Name="OpenIdConnect"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="METADATA">https://{identity_server_hostname}/identity/.well-known/openid-configuration</Item>
<Item Key="ProviderName">https://{identity_server_hostname}/identity</Item>
<Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
<Item Key="IdTokenAudience">00000000-0000-0000-0000-000000000000</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid profile customScope</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="AccessTokenResponseFormat">json</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_IdentityServerAppSecret"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="IdentityServer" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="tid" />
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="sub" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
</TechnicalProfile>
基本上,在 IdentityServer 端进行身份验证后,我被重定向回初始化登录的网页,然后出现此错误:
AADB2C:发生异常。
关联 ID:6797f691-4adb-4963-ad12-f31add3e1919
时间戳:2018-08-23 08:42:54Z
在针对给定的相关 ID 分析 AAD B2C 上的日志时,我没有发现任何有用的信息可以引导我找到可能的解决方案。
昨天,在安静地花了很长时间尝试这么多不同的事情之后,我终于明白了为什么我们没有把所有的索赔都归还给客户。它们实际上并不存在于身份令牌中,而仅存在于访问令牌中。 AAD B2C 使用第一个身份令牌,同时执行自定义策略中定义的映射,这就是重点。最后我不得不在 IdentityServer3 端做一些小改动(看看下面的代码)。
这就是负责发布声明并生成身份和访问令牌的 class 现在的样子:
public class CustomClaimsProvider : DefaultClaimsProvider
{
private readonly IIndex claimDefinitions;
public CustomClaimsProvider(
IUserService users,
IIndex<string, IClaimsDefinition> claimDefinitions)
: base(users)
{
this.claimDefinitions = claimDefinitions;
}
public override async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(
ClaimsPrincipal subject,
Client client,
IEnumerable<Scope> scopes,
bool includeAllIdentityClaims,
ValidatedRequest request)
{
var claims = await base.GetIdentityTokenClaimsAsync(subject, client, scopes, includeAllIdentityClaims, request).ConfigureAwait(false);
return GetAdditionalClaims(scopes, claims);
}
public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(
ClaimsPrincipal subject,
Client client,
IEnumerable<Scope> scopes,
ValidatedRequest request)
{
var claims = await base.GetAccessTokenClaimsAsync(subject, client, scopes, request).ConfigureAwait(false);
return GetAdditionalClaims(scopes, claims);
}
private IEnumerable<Claim> GetAdditionalClaims(IEnumerable<Scope> scopes, IEnumerable<Claim> claims)
{
var scopesList = scopes.ToList();
var claimsList = claims.ToList();
foreach (var scope in scopesList.Select(x => x.Name))
{
if (claimDefinitions.TryGetValue(scope, out IClaimsDefinition claimDef))
{
claimsList.AddRange(claimDef.GetClaims(claims));
}
}
return claimsList;
}
}
所以,要点是,如果您想将一些额外的声明作为身份令牌的一部分,您还应该覆盖派生自 DefaultClaimsProvider 的 class 中的 GetIdentityTokenClaimsAsync 方法。
非常感谢 Microsoft 支持,他们帮助我解决了很多问题。
尽管我已经很好地设置了所有声明映射,因此它们与我们的 Identity Server 3 发布的匹配,但我们在 Azure AD 端似乎没有这些值。姓名和电子邮件是可以用作示例的声明。奇怪的是,这只发生在自定义身份提供者 (Open ID Connect) 中,而例如 Facebook 内置的身份提供者运行良好,并接受从 IdP 收到的声明。有没有人做过这项工作?
[编辑]
此外,我还尝试通过此处建议的自定义策略来实现此目的:
<TechnicalProfile Id="IdentityServerProfile">
<DisplayName>IdentityServer</DisplayName>
<Description>Login with your IdentityServer account</Description>
<Protocol Name="OpenIdConnect"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="METADATA">https://{identity_server_hostname}/identity/.well-known/openid-configuration</Item>
<Item Key="ProviderName">https://{identity_server_hostname}/identity</Item>
<Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
<Item Key="IdTokenAudience">00000000-0000-0000-0000-000000000000</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid profile customScope</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="AccessTokenResponseFormat">json</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_IdentityServerAppSecret"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="IdentityServer" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="tid" />
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="sub" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
</TechnicalProfile>
基本上,在 IdentityServer 端进行身份验证后,我被重定向回初始化登录的网页,然后出现此错误: AADB2C:发生异常。 关联 ID:6797f691-4adb-4963-ad12-f31add3e1919 时间戳:2018-08-23 08:42:54Z
在针对给定的相关 ID 分析 AAD B2C 上的日志时,我没有发现任何有用的信息可以引导我找到可能的解决方案。
昨天,在安静地花了很长时间尝试这么多不同的事情之后,我终于明白了为什么我们没有把所有的索赔都归还给客户。它们实际上并不存在于身份令牌中,而仅存在于访问令牌中。 AAD B2C 使用第一个身份令牌,同时执行自定义策略中定义的映射,这就是重点。最后我不得不在 IdentityServer3 端做一些小改动(看看下面的代码)。
这就是负责发布声明并生成身份和访问令牌的 class 现在的样子:
public class CustomClaimsProvider : DefaultClaimsProvider
{ private readonly IIndex claimDefinitions;
public CustomClaimsProvider(
IUserService users,
IIndex<string, IClaimsDefinition> claimDefinitions)
: base(users)
{
this.claimDefinitions = claimDefinitions;
}
public override async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(
ClaimsPrincipal subject,
Client client,
IEnumerable<Scope> scopes,
bool includeAllIdentityClaims,
ValidatedRequest request)
{
var claims = await base.GetIdentityTokenClaimsAsync(subject, client, scopes, includeAllIdentityClaims, request).ConfigureAwait(false);
return GetAdditionalClaims(scopes, claims);
}
public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(
ClaimsPrincipal subject,
Client client,
IEnumerable<Scope> scopes,
ValidatedRequest request)
{
var claims = await base.GetAccessTokenClaimsAsync(subject, client, scopes, request).ConfigureAwait(false);
return GetAdditionalClaims(scopes, claims);
}
private IEnumerable<Claim> GetAdditionalClaims(IEnumerable<Scope> scopes, IEnumerable<Claim> claims)
{
var scopesList = scopes.ToList();
var claimsList = claims.ToList();
foreach (var scope in scopesList.Select(x => x.Name))
{
if (claimDefinitions.TryGetValue(scope, out IClaimsDefinition claimDef))
{
claimsList.AddRange(claimDef.GetClaims(claims));
}
}
return claimsList;
}
}
所以,要点是,如果您想将一些额外的声明作为身份令牌的一部分,您还应该覆盖派生自 DefaultClaimsProvider 的 class 中的 GetIdentityTokenClaimsAsync 方法。
非常感谢 Microsoft 支持,他们帮助我解决了很多问题。