ADB2C策略中ValidationTechnicalProfile调用REST接口失败求助
问题:ValidationTechnicalProfile添加REST调用后登录流程失败
问题现象
- 在ValidationTechnicalProfile中加入以下配置后,登录流程直接失败:
<ValidationTechnicalProfile ReferenceId="REST-acquireaccesstoken"/>
- 删掉这段配置,登录就能正常走通;加回去就会抛出以下错误:
"Key": "Exception", "Value": { "Kind": "Handled", "HResult": "80131500", "Message": "Invalid username or password.", "Data": { "IsPolicySpecificError": false } }
- 同一个
REST-AcquireAccessTokenTechnicalProfile放在OrchestrationStep里调用完全正常,Application Insights日志只显示上面的错误,没提供更多排查线索。
涉及的TechnicalProfile配置
<TechnicalProfile Id="REST-AcquireAccessToken"> <DisplayName></DisplayName> <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> <Metadata> <Item Key="ServiceUrl">https://login.microsoftonline.com/xxxxxxxxxx/oauth2/v2.0/token</Item> <Item Key="AuthenticationType">Basic</Item> <Item Key="SendClaimsIn">Form</Item> <Item Key="AllowInsecureAuthInProduction">true</Item> </Metadata> <CryptographicKeys> <Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_ClientId" /> <Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_Secret" /> </CryptographicKeys> <InputClaims> <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" AlwaysUseDefaultValue="true" /> <InputClaim ClaimTypeReferenceId="scope" DefaultValue="api://xxxxxxxx/.default" AlwaysUseDefaultValue="true" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" /> </OutputClaims> <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" /> </TechnicalProfile>
原因分析
ValidationTechnicalProfile是在用户提交用户名密码之后、主验证流程完成之前执行的,这时候B2C会自动把用户输入的signInName、password这类凭证声明传递给ValidationTechnicalProfile。你的REST TP设置了SendClaimsIn: Form,导致这些额外的用户凭证被一起发到Azure AD的token端点,端点识别不了这些参数,就返回了“Invalid username or password”这个通用错误。
而在OrchestrationStep里调用时,不会自动注入这些用户凭证声明,请求里只有grant_type和scope,所以能正常拿到token。
解决方案
方案1:修改REST TP,阻止额外声明传递
在REST-AcquireAccessToken的Metadata里加IncludeClaimResolvingInClaimsHandling: true,同时在InputClaims里明确把不需要的用户凭证声明设为空值,避免发送到端点:
<TechnicalProfile Id="REST-AcquireAccessToken"> <!-- 其他原有配置不变 --> <Metadata> <!-- 保留原有Metadata项 --> <Item Key="IncludeClaimResolvingInClaimsHandling">true</Item> </Metadata> <InputClaims> <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" AlwaysUseDefaultValue="true" /> <InputClaim ClaimTypeReferenceId="scope" DefaultValue="api://xxxxxxxx/.default" AlwaysUseDefaultValue="true" /> <!-- 新增这两行,清空用户凭证声明 --> <InputClaim ClaimTypeReferenceId="signInName" DefaultValue="" AlwaysUseDefaultValue="true" /> <InputClaim ClaimTypeReferenceId="password" DefaultValue="" AlwaysUseDefaultValue="true" /> </InputClaims> <!-- 其他原有配置不变 --> </TechnicalProfile>
方案2:把REST TP移到OrchestrationStep执行
既然这个TP在OrchestrationStep里能正常工作,直接把它移到登录流程里合适的步骤(比如用户验证成功之后),别放在ValidationTechnicalProfile里,这样既能获取token,又不会干扰用户凭证的验证。
方案3:用ClaimsTransformation过滤无用声明
创建一个ClaimsTransformation来清除用户凭证声明,在调用ValidationTechnicalProfile之前应用这个转换,确保传给REST TP的只有必要参数。
内容的提问来源于stack exchange,提问作者Ray
相关产品推荐
相关产品推荐

