简体   繁体   English

在 B2C 自定义策略中从 Azure AD 获取 singin email

[英]Get singin email from Azure AD in a B2C custom policy

In AAD B2C I have users created with 2 identities.在 AAD B2C 中,我创建了具有 2 个身份的用户。 I used graph to create them with this body:我用图形用这个主体创建它们:

{
  "displayName": "John Doe",
  "mail":"johndoe19287456@gmail.com",
  "identities": [
    {
      "signInType": "userName",
      "issuer": "mytenant.onmicrosoft.com",
      "issuerAssignedId": "606198"
    },
    {
      "signInType": "emailAddress",
      "issuer": "mytenant.onmicrosoft.com",
      "issuerAssignedId": "johndoe19287456@gmail.com"
    }
  ],
  "passwordProfile" : {
    "password": "Soleil!23",
    "forceChangePasswordNextSignIn": false
  },
  "passwordPolicies": "DisablePasswordExpiration"
}

This allow the user to connect either with an email ( johndoe19287456@gmail.com ) or an ID ( 606198 ).这允许用户使用 email ( johndoe19287456@gmail.com ) 或 ID ( 606198 ) 进行连接。

When a user input his ID and then click on the "Forgot password?"当用户输入他的 ID 然后点击“忘记密码?” link, I'd like to get the email value from AAD so the user cannot input whatever he wants.链接,我想从 AAD 获取 email 值,这样用户就无法输入他想要的任何内容。 But I'd still like it to be "verified" by sending a code to that email address.但我仍然希望通过向该 email 地址发送代码来“验证”它。 I have 2 problems:我有两个问题:

  • I can't fnd a way to get the email value from AzureActiveDirectoryProvider我找不到从 AzureActiveDirectoryProvider 获取 email 值的方法
  • I can't find a way to populate the Verified.Email field (and make it readonly).我找不到填充 Verified.Email 字段的方法(并将其设为只读)。

Here's a sample of one of the many things I've tried yet.这是我尝试过的许多事情之一的示例。

Building blocks custom claims:构建块自定义声明:

      <ClaimType Id="ReadOnlyEmail">
        <DisplayName>Verified Email Address</DisplayName>
        <DataType>string</DataType>
        <UserInputType>Readonly</UserInputType>
      </ClaimType>
      <ClaimType Id="emailFromAAD">
        <DisplayName>Email from AAD</DisplayName>
        <DataType>string</DataType>
        <UserHelpText />
        <UserInputType>Readonly</UserInputType>
      </ClaimType>
      <ClaimType Id="readOnlySignInName">
        <DisplayName>Sign in name</DisplayName>
        <DataType>string</DataType>
        <UserHelpText />
        <UserInputType>Readonly</UserInputType>
      </ClaimType>
      <ClaimType Id="emailValue">
        <DisplayName>Matched mail</DisplayName>
        <DataType>string</DataType>
      </ClaimType>
      <ClaimType Id="isEmailBoolean">
        <DisplayName>is Email</DisplayName>
        <DataType>boolean</DataType>
      </ClaimType>
      <ClaimType Id="strongAuthenticationEmailAddress">
        <DisplayName>string</DisplayName>
        <DataType>string</DataType>
        <AdminHelpText>Email address that the user can use for strong authentication.</AdminHelpText>
        <UserHelpText>Email address to use for strong authentication.</UserHelpText>
        <UserInputType>TextBox</UserInputType>
      </ClaimType>

Claims transformation:声明转换:

<ClaimsTransformation Id="CopySignInNameFromReadOnly" TransformationMethod="FormatStringClaim">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="readOnlySignInName" TransformationClaimType="inputClaim" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="stringFormat" DataType="string" Value="{0}" />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="signInName" TransformationClaimType="outputClaim" />
        </OutputClaims>
      </ClaimsTransformation>

      <!-- If signin name match the regex, it is an email identifier. Oterwise, it'll be considered as username -->
      <ClaimsTransformation Id="isEmail" TransformationMethod="setClaimsIfRegexMatch">
        <InputClaims>
          <InputClaim ClaimTypeReferenceId="readOnlySignInName" TransformationClaimType="claimToMatch" />
        </InputClaims>
        <InputParameters>
          <InputParameter Id="matchTo" DataType="string" Value="[^@]+@[^\.]+\..+" />
          <InputParameter Id="outputClaimIfMatched" DataType="string" Value="isEmail" />
        </InputParameters>
        <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="emailValue" TransformationClaimType="outputClaim" />
          <OutputClaim ClaimTypeReferenceId="isEmailBoolean" TransformationClaimType="regexCompareResultClaim" />
        </OutputClaims>
      </ClaimsTransformation>

Technical profiles:技术简介:

<!-- Password reset step 1b - Included in step SelfAsserted-LocalAccountLookup-Combined-PwdReset 
        That's where the input claim is define. signInName = the Username field on the screen -->
        <TechnicalProfile Id="SelfAsserted-LocalAccountLookup-Combined-SignUp">
          <DisplayName>Local Account Sign Up</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="IncludeClaimResolvingInClaimsHandling">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="readOnlySignInName" DefaultValue="{OIDC:LoginHint}" AlwaysUseDefaultValue="true" />
          </InputClaims>
          <OutputClaims>
          <OutputClaim ClaimTypeReferenceId="readOnlySignInName" Required="true" />
            <OutputClaim ClaimTypeReferenceId="isEmailBoolean" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CopySignInNameFromReadOnly" />
          </OutputClaimsTransformations>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="regexAnalysisUsername" />
          </ValidationTechnicalProfiles>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>

<!-- Password reset step 1a. Includes SelfAsserted-LocalAccountLookup-Combined-SignUp 
        Input claim is defined in this. Here, we define output claims -->
        <TechnicalProfile Id="SelfAsserted-LocalAccountLookup-Combined-PwdReset">
          <DisplayName>Reset password</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="setting.showCancelButton">false</Item>
            <Item Key="IpAddressClaimReferenceId">IpAddress</Item>
            <Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
            <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
          </Metadata>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="readOnlySignInName" Required="true" />
            <OutputClaim ClaimTypeReferenceId="isEmailBoolean" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="emailFromAAD" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingIdentifier" />
            <ValidationTechnicalProfile ReferenceId="regexAnalysisUsername" />
          </ValidationTechnicalProfiles>
          <IncludeTechnicalProfile ReferenceId="SelfAsserted-LocalAccountLookup-Combined-SignUp" />
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>

        <!-- Password reset step 1c. Verify signin name on the "Continue" button clicked in the first screen -->
        <TechnicalProfile Id="AAD-UserReadUsingIdentifier">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="readOnlySignInName" PartnerClaimType="signInNames" Required="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="emailFromAAD" PartnerClaimType="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
          </OutputClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>

<!-- Passwod reset step 2. Only if sign in data was a username -->
        <TechnicalProfile Id="LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress">
          <DisplayName>Reset password using username</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <!-- Other values maybe defined in localized api.selfasserted.fr and api.selfasserted.en -->
            <Item Key="IpAddressClaimReferenceId">IpAddress</Item>
            <Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
            <Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
            <Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">An account could not be found for the provided User ID and email combination.</Item>
            <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
            <Item Key="LocalAccountType">Username</Item>
            <Item Key="LocalAccountProfile">true</Item>
            <!-- Reduce the default self-asserted retry limit of 7 for the reset journey -->
            <Item Key="setting.retryLimit">5</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
          </CryptographicKeys>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="readOnlySignInName" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="readOnlySignInName" Required="true" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" DefaultValue="strongAuthenticationEmailAddress" Required="true" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" />
            <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
            <OutputClaim ClaimTypeReferenceId="emailFromAAD" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingUserNameAndValidateStrongAuthenticationEmailAddress" />
          </ValidationTechnicalProfiles>
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>

For now, I get the first screen with the readonly ID working.现在,我得到了第一个带有只读 ID 的屏幕。

在此处输入图像描述

The next screen presents the textboxes for email. The Email from AAD shouldn't visible.下一个屏幕显示 email 的文本框。来自 AAD 的 Email 应该不可见。

在此处输入图像描述

But anyway it is empty, showing that it didn't get anything from AAD or I failed to properly store it in the claim bag or pass it down.但无论如何它是空的,表明它没有从 AAD 得到任何东西,或者我没有将它正确地存放在索赔袋中或将其传递下去。 Note that I have tried getting the value both from "strongAuthenticationEmailAddress" and "signInNames.emailAddress" based on Microsoft documentation but none of it works.请注意,我已尝试根据 Microsoft 文档从“strongAuthenticationEmailAddress”和“signInNames.emailAddress”获取值,但均无效。 Maybe it's in the way I define my output claim with PartnerClaimType in the AAD-UserReadUsingIdentifier profile?也许这是我在 AAD-UserReadUsingIdentifier 配置文件中使用 PartnerClaimType 定义我的 output 声明的方式?

To make it clear for everyone, here's what I'd like to have.为了让每个人都清楚,这是我想要的。 A simple page with 2 reaonly fields with a button to send the code and then another one to continue after the code has been verified.一个简单的页面,包含 2 个只包含一个按钮的 reaonly 字段,用于发送代码,然后另一个按钮在验证代码后继续。

在此处输入图像描述

Can anyone help me with this one?谁能帮我解决这个问题?

I started from the B2C custom policies starter pack and added customization from this community repo .我从 B2C 自定义策略启动包开始,并从这个社区 repo添加了自定义。

UPDATE Here is what I get from MS Graph when querying for my user:更新这是我在查询用户时从 MS Graph 获得的信息:

{
    "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users(identities,id,displayName,mail,surname,userPrincipalName,extension_06a19ccd80a0430c9730c62e4d96c895_ClientID,extension_06a19ccd80a0430c9730c62e4d96c895_requiresMigration)/$entity",
    "id": "051e***************",
    "displayName": "test - Tests2",
    "mail": "johndoe19287456@gmail.com",
    "surname": null,
    "userPrincipalName": "051ea****************@mytenant.onmicrosoft.com",
    "identities": [
        {
            "signInType": "emailAddress",
            "issuer": "mytenant.onmicrosoft.com",
            "issuerAssignedId": "johndoe19287456@gmail.com"
        },
        {
            "signInType": "userName",
            "issuer": "mytenant.onmicrosoft.com",
            "issuerAssignedId": "606198"
        },
        {
            "signInType": "userPrincipalName",
            "issuer": "mytenant.onmicrosoft.com",
            "issuerAssignedId": "051ea****************@mytenant.onmicrosoft.com"
        }
    ]
}

You must provide the emailFromAAD as an input claim in LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress for it to be pre populated here.您必须提供 emailFromAAD 作为LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress中的输入声明,以便在此处预填充。

https://learn.microsoft.com/en-us/azure/active-directory-b2c/self-asserted-technical-profile#input-claims https://learn.microsoft.com/en-us/azure/active-directory-b2c/self-asserted-technical-profile#input-claims

          <InputClaims>
            <InputClaim ClaimTypeReferenceId="readOnlySignInName" PartnerClaimType="signInNames" Required="true" />
            <InputClaim ClaimTypeReferenceId="emailFromAAD" />
          </InputClaims>

Now it will be prepopulated on this page.现在它将预先填充在此页面上。

If you want to force verification of this email, copy it into a read only claim using a claim transform, then do:如果要强制验证此 email,请使用声明转换将其复制到只读声明中,然后执行以下操作:

<OutputClaim ClaimTypeReferenceId="readOnlyEmailFromAAD" PartnerClaimType="Verified.Email" Required="true" />

I managed to get email address from AAD by following Jas Suri - MSFT advice with a few other things.我按照 Jas Suri - MSFT 的建议以及其他一些事情设法从 AAD 获得了 email 地址。 So just to sum things up here's what I did.因此,总结一下这就是我所做的。 I modified the Validation TP AAD-UserReadUsingIdentifier by replacing the output claim emailFromAAD simply by signInNames.emailAddress (no more PartnerClaimType).我修改了验证 TP AAD-UserReadUsingIdentifier ,只需将 output 声明emailFromAAD替换为signInNames.emailAddress (不再是 PartnerClaimType)。 In the LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress TP, I added the InputClaim emailFromAAD that I populate with a CopyClaim input claims transformation.LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress TP 中,我添加了使用emailFromAAD输入声明转换填充的 InputClaim emailFromAAD。 I also cleaned up the first TP of the journey SelfAsserted-LocalAccountLookup-Combined-PwdReset :我还清理了旅程的第一个 TP SelfAsserted-LocalAccountLookup-Combined-PwdReset

<ClaimsTransformation Id="CopySignInEmailAddressToEmail" TransformationMethod="CopyClaim">
    <InputClaims>
      <InputClaim ClaimTypeReferenceId="signInNames.emailAddress" TransformationClaimType="inputClaim" />
    </InputClaims>
    <OutputClaims>
      <OutputClaim ClaimTypeReferenceId="emailFromAAD" TransformationClaimType="outputClaim" />
    </OutputClaims>
</ClaimsTransformation>

<TechnicalProfile Id="SelfAsserted-LocalAccountLookup-Combined-PwdReset">
          <DisplayName>Reset password</DisplayName>
          <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
          <Metadata>
            <Item Key="setting.showCancelButton">false</Item>
            <Item Key="IpAddressClaimReferenceId">IpAddress</Item>
            <Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
            <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
          </Metadata>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="readOnlySignInName" Required="true" />
            <OutputClaim ClaimTypeReferenceId="isEmailBoolean" />
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
          </OutputClaims>
          <ValidationTechnicalProfiles>
            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingIdentifier" />
            <ValidationTechnicalProfile ReferenceId="regexAnalysisReadOnlyUsername" />
          </ValidationTechnicalProfiles>
          <IncludeTechnicalProfile ReferenceId="SelfAsserted-LocalAccountLookup-Combined-SignUp" />
          <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
        </TechnicalProfile>

<TechnicalProfile Id="AAD-UserReadUsingIdentifier">
          <Metadata>
            <Item Key="Operation">Read</Item>
            <Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
          </Metadata>
          <IncludeInSso>false</IncludeInSso>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="readOnlySignInName" PartnerClaimType="signInNames" Required="true" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="objectId" />
            <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" />
            <OutputClaim ClaimTypeReferenceId="strongAuthenticationEmailAddress" />
          </OutputClaims>
          <IncludeTechnicalProfile ReferenceId="AAD-Common" />
        </TechnicalProfile>
      
<TechnicalProfile Id="LocalAccountDiscoveryUsingUserNameAndValidateStrongAuthenticationEmailAddress">
      <DisplayName>Reset password using username</DisplayName>
      <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      <Metadata>
        <!-- Other values maybe defined in localized api.selfasserted.fr and api.selfasserted.en -->
        <Item Key="IpAddressClaimReferenceId">IpAddress</Item>
        <Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
        <Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
        <Item Key="UserMessageIfClaimsTransformationStringsAreNotEqual">An account could not be found for the provided User ID and email combination.</Item>
        <Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
        <Item Key="LocalAccountType">Username</Item>
        <Item Key="LocalAccountProfile">true</Item>
        <!-- Reduce the default self-asserted retry limit of 7 for the reset journey -->
        <Item Key="setting.retryLimit">5</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
      </CryptographicKeys>
      <InputClaimsTransformations>
        <InputClaimsTransformation ReferenceId="CopySignInEmailAddressToEmail" />
      </InputClaimsTransformations>
      <InputClaims>
        <InputClaim ClaimTypeReferenceId="readOnlySignInName" />
        <InputClaim ClaimTypeReferenceId="emailFromAAD" />
      </InputClaims>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="readOnlySignInName" Required="true" />
        <OutputClaim ClaimTypeReferenceId="emailFromAAD" PartnerClaimType="Verified.Email" Required="true" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" />
      </OutputClaims>
      <ValidationTechnicalProfiles>
        <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingUserNameAndValidateStrongAuthenticationEmailAddress" />
      </ValidationTechnicalProfiles>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
    </TechnicalProfile>
      

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Azure AD B2C 自定义策略中自定义声明的本地化 - Localization of custom claim in Azure AD B2C custom policy Azure b2c自定义策略,LinkedIn Identity Provider,无法获取email地址 - Azure b2c custom policy, LinkedIn Identity Provider, unable to get email address Azure AD B2C 自定义策略验证代码并在同一操作中继续 - Azure AD B2C Custom Policy Verify Code & Continue in same Action 在注册过程中将“手机”存储在联系信息中 - Azure AD B2C 自定义策略 + MFA - Store "mobilePhone" in contact info during registration - Azure AD B2C Custom policy + MFA 本地化 TemplateId InputParameter 值在 Azure B2C 自定义策略与 SendGrid 自定义 email 验证 - Localize TemplateId InputParameter value in Azure B2C custom policy with SendGrid custom email verification Azure B2C - 无法让 B2C 用户流与另一个 Azure AD 实例一起作为自定义身份提供商 - Azure B2C - Can't get a B2C user flow to work with another Azure AD instance as a custom identity provider Azure B2C - 自定义策略 - 密码更改 - Azure B2C - Custom Policy - Password Change azure B2c无缝用户迁移自定义策略错误 - azure B2c Seamless user migration custom policy error 如何为 Azure AD B2C 自定义电子邮件配置 SMTP? - How to configure SMTP for Azure AD B2C custom emails? Azure AD B2C 忘记密码用文本而不是 Email? - Azure AD B2C Forgot Password with Text instead of Email?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM