Azure AD B2C自定义JIT迁移用户流二次登录提示密码无效
Azure AD B2C 自定义JIT迁移策略二次登录报凭据无效问题
问题描述
我在Azure AD B2C中搭建自定义用户流,基本直接复用了官方即时(JIT)用户迁移v2版本的示例策略,做了如下调整:
- 禁用了Facebook、Google等第三方身份提供方
- 关闭了自助注册、密码重置功能
- 仅保留基础的本地账号登录表单
实际测试时出现稳定复现的异常:
- 用户首次登录可以正常完成账号迁移,成功通过认证
- 同一个用户第二次登录直接返回错误:
The username or password provided in the request are invalid. - 多次验证输入凭据完全正确,包括使用Chrome自动填充首次登录时保存的密码,确认不存在输入错误
- 新建标准内置
SignUpSignIn用户流,用刚迁移完成的同个账号密码可以正常登录,证明密码已经正确写入B2C目录
我判断是自定义策略里login-NonInteractive验证技术配置文件存在配置错误,把自有策略文件和官方示例逐行比对也没定位到差异,求排查方向。
相关策略文件因内容长度限制无法直接粘贴全量内容,已托管至Pastebin:
- SignUpOrSignIn.xml:片段ID M1iYaAFU
- TrustFrameworkExtension.xml:片段ID psA0mNKH
- TrustFrameworkBase.xml:片段ID xZy8VfDE
问题更新
以下为从Application Insights导出的核心报错日志片段:
[ { "Kind": "Headers", "Content": { "UserJourneyRecorderEndpoint": "urn:journeyrecorder:applicationinsights", "CorrelationId": "403025e3-e919-4662-a000-e98e874947fa", "EventInstance": "Event:SELFASSERTED", "TenantId": "likvidostaging.onmicrosoft.com", "PolicyId": "B2C_1A_JITMigraion_signup_signin" } }, { "Kind": "Transition", "Content": { "EventName": "SELFASSERTED", "StateName": "Initial" } }, { "Kind": "HandlerResult", "Content": { "Result": false, "RecorderRecord": { "Values": [ { "Key": "Validation", "Value": { "Values": [ { "Key": "TechnicalProfileEnabled", "Value": { "EnabledRule": "Always", "EnabledResult": true, "TechnicalProfile": "REST-UserMigration-LocalAccount-SignIn" } }, { "Key": "Precondition", "Value": { "Type": 1, "ExecuteActionsIf": true, "ActionTypes": [1], "Values": ["needToMigrate", "local"] } }, { "Key": "TechnicalProfileEnabled", "Value": { "EnabledRule": "Always", "EnabledResult": true, "TechnicalProfile": "login-NonInteractive" } }, { "Key": "Exception", "Value": { "Kind": "Handled", "HResult": "80131500", "Message": "The username or password provided in the request are invalid.", "Data": { "IsPolicySpecificError": false } } } ] } } ] }, "Exception": { "Kind": "Handled", "HResult": "80131500", "Message": "The username or password provided in the request are invalid.", "Data": { "IsPolicySpecificError": false } }, "PredicateResult": "False" } } ]
排查方案
这是B2C JIT迁移场景非常典型的配置错误,我之前做企业迁移项目踩过一模一样的坑,按下面几个点逐一排查即可:
- 先看执行顺序逻辑:从日志能看到,你的迁移REST API没有加正确的已迁移用户跳过逻辑。用户首次迁移完成写入B2C目录时,必须给用户对象加一个自定义扩展字段标记「已迁移」,二次登录时编排步骤要先通过读取用户接口拿到这个标记,识别到已迁移用户就完全跳过迁移REST API调用,直接走
login-NonInteractive做密码校验。你现在的配置是不管用户有没有迁过都会先触发迁移接口,大概率是迁移接口对已存在用户的返回逻辑有问题,要么返回了异常声明,要么错误修改了密码相关字段,直接干扰后续密码校验流程。 - 最高发的根因:检查你用来写入迁移用户的AAD技术配置文件(一般是
AAD-UserWriteUsingLogonEmail或者自定义的写入技术配置文件),是不是多写了<PersistedClaim ClaimTypeReferenceId="password" />这行?绝对不能持久化password声明。B2C创建本地账号时会自动把传入的明文密码做合规哈希存储,要是额外加了持久化password的配置,会把传入的明文直接存到用户属性里覆盖正确的密码哈希——首次登录因为账号刚创建会话直接放行,二次登录走密码校验哈希对不上,就会报用户名密码错误。我当时踩这个坑查了整整一天,删掉这行配置重新上传策略就恢复正常了。 - 检查
login-NonInteractive的参数配置:里面的client_id必须填租户下ProxyIdentityExperienceFramework应用的客户端ID,resource必须填IdentityExperienceFramework应用的客户端ID,这两个值填错、搞反,哪怕密码100%正确也会返回通用的用户名密码无效报错。 - 最后校验密码策略一致性:你日志里全局配置的密码策略是
DisablePasswordExpiration, DisableStrongPassword,确认创建迁移用户时给用户设置的密码策略和这个值完全一致,策略不匹配也会导致哈希校验失败。
内容的提问来源于stack exchange,提问作者Søren Pedersen
相关产品推荐
相关产品推荐

