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

Azure AD B2C:login-NonInteractive直接调用POST失效及替代方案咨询

Azure AD B2C 内部M2M场景JWT签发问题解决

需求

我需要创建一个支持通过查询参数传入密码的端点,用于微服务间内部M2M场景签发JWT。该密码仅用于限制授权服务访问,无需极高安全性。

遇到的问题

在Azure AD B2C中,login-NonInteractive技术配置文件仅能通过Self-Asserted技术配置文件的ValidationTechnicalProfile调用才能正常工作(此方式会带UI界面)。但直接从编排步骤调用时,即使配置了<Item Key="HttpBinding">POST</Item>,请求仍以GET方法发送,而目标端点仅接受OPTIONS和POST请求,导致报错。

带Self-Asserted UI的有效代码

<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Username">
    <DisplayName>Local Account Signin</DisplayName>
    <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    <Metadata>
      <Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
      <Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">The last names you provided are not the same</Item>
      <Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
    </Metadata>
    <IncludeInSso>false</IncludeInSso>
    <!-- <InputClaims>
      <InputClaim ClaimTypeReferenceId="signInName" />
    </InputClaims> -->
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
      <OutputClaim ClaimTypeReferenceId="password" Required="true" />
      <OutputClaim ClaimTypeReferenceId="objectId" />
      <OutputClaim ClaimTypeReferenceId="authenticationSource" />
    </OutputClaims>
    <ValidationTechnicalProfiles>
      <ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
    </ValidationTechnicalProfiles>
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
  </TechnicalProfile>

login-NonInteractive配置代码

<TechnicalProfile Id="login-NonInteractive">
  <DisplayName>Local Account SignIn</DisplayName>
  <Protocol Name="OpenIdConnect" />
  <Metadata>
    <Item Key="ProviderName">https://sts.windows.net/</Item>
    <Item Key="METADATA">https://login.microsoftonline.com/{tenant}/.well-known/openid-configuration</Item>
    <Item Key="authorization_endpoint">https://login.microsoftonline.com/{tenant}/oauth2/token</Item>
    <Item Key="response_types">id_token</Item>
    <Item Key="response_mode">query</Item>
    <Item Key="scope">email openid</Item>
    <!-- <Item Key="grant_type">password</Item> -->

    <!-- Policy Engine Clients -->
    <Item Key="UsePolicyInRedirectUri">false</Item>
    <Item Key="HttpBinding">POST</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" Required="true" />
    <InputClaim ClaimTypeReferenceId="password" Required="true" />
    <InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" AlwaysUseDefaultValue="true" />
    <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" AlwaysUseDefaultValue="true" />
    <InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
    <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid" />
    <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
    <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
    <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
    <OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="upn" />
    <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
  </OutputClaims>
</TechnicalProfile>

问题

  1. 是否有无需依赖Self-Asserted技术配置文件即可让login-NonInteractive正常发送POST请求的解决方法?
  2. 若没有,如何通过REST技术配置文件或OAuth2配置文件实现相同的用户密码验证及JWT签发功能(优先避免已弃用的ROPC)?

解决方案

问题1:无需Self-Asserted调用login-NonInteractive发送POST请求的方法

直接从编排步骤调用login-NonInteractive时,即便配置了HttpBinding=POST仍用GET请求,是因为OpenID Connect技术配置文件在非验证场景下的默认行为限制,目前没有直接绕过的方式——login-NonInteractive设计上就是作为验证步骤(通过Self-Asserted的ValidationTechnicalProfile)来触发,此时才会遵循POST绑定配置。

如果必须避免UI,可尝试以下两种思路:

  • 隐藏Self-Asserted UI:修改Self-Asserted技术配置文件的元数据,将ContentDefinitionReferenceId指向一个空白/隐藏的内容定义,同时通过Claims Transformation预先填充signInName和password(从查询参数提取),这样用户看不到UI,但仍能触发验证步骤发送POST请求。
  • 使用Custom Policy的API Connector:通过REST技术配置文件先处理查询参数提取,再调用内部验证逻辑,但此方式需要额外的后端服务支持。

问题2:用REST/OAuth2实现用户验证与JWT签发(避免ROPC)

方案一:REST技术配置文件+自定义验证服务

  1. 创建一个REST API服务,负责接收查询参数中的signInName和password,调用MS Graph API验证用户凭据(使用应用权限调用users/getByUserPrincipalName并校验密码,需启用目录读写权限)。
  2. 在Azure AD B2C自定义策略中添加REST技术配置文件,直接从编排步骤调用该API:
<TechnicalProfile Id="REST-ValidateUserCredentials">
  <DisplayName>Validate User Credentials via REST</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://your-api-domain.com/validate-credentials</Item>
    <Item Key="SendClaimsIn">QueryString</Item>
    <Item Key="AuthenticationType">None</Item>
  </Metadata>
  <InputClaims>
    <InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" />
    <InputClaim ClaimTypeReferenceId="password" PartnerClaimType="password" />
  </InputClaims>
  <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="oid" />
    <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
    <!-- 其他需要的用户信息声明 -->
  </OutputClaims>
  <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
  1. 在编排步骤中调用该REST技术配置文件,验证通过后继续执行JWT签发流程(使用JwtIssuer技术配置文件)。

方案二:使用Client Credentials Flow(纯M2M场景推荐)

如果你的场景是严格的微服务间M2M,无需模拟用户身份,更合适的方式是使用Azure AD的Client Credentials Flow:

  • 为每个微服务注册Azure AD应用,配置应用权限(而非委派权限)。
  • 微服务直接调用Azure AD令牌端点,使用客户端ID和客户端密钥(或证书)获取JWT,无需用户密码。
  • 此方式完全符合M2M场景最佳实践,避免了密码传递的风险,也不需要自定义策略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:25:18