Azure B2C中ContentDefinition使用完整动态URI报错求助
更新说明
客户正在搭建的Azure B2C租户需响应两个不同URL:
- https://www.url1.com
- https://www.url2.com
二者业务规则、用户旅程完全一致,仅UI样式不同。相关样式文件(CSS、图片、页面布局)分别存储在不同Azure Blob Storage中。由于无法提前知晓请求URL,需调用外部API根据请求主机名获取对应完整Blob存储URL,将其作为ContentDefinition的<LoadUri>值,但直接使用完整动态URI时遇到限制。
原问题
尝试为ContentDefinition配置动态URI时触发验证错误:
Validation failed: 1 validation error(s) found in policy "MY POLICY NAME" of tenant "mytenantname.onmicrosoft.com". The format if the URI 'Any-Text' is invalid. The format of the URI 'Any-Text' is invalid.
外部API返回响应格式如下:
{ "loadUri": "https://my.cdn.com/template.html" }
将loadUri存入自定义声明后,ContentDefinition配置如下:
<ContentDefinition Id="api.signuporsignin"> <LoadUri>{Claim:loadUri}</LoadUri> <RecoveryUri>~/common/default_page_error.html</RecoveryUri> <DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.5</DataUri> <Metadata> <Item Key="DisplayName">Signin and Signup</Item> </Metadata> </ContentDefinition>
官方文档表明可使用声明生成动态URI,但仅支持固定协议+主机名的部分动态场景(例如<LoadUri>https://www.my.cdn.com/{Claim:loadUri}</LoadUri>)。当尝试使用完整动态URI(如<LoadUri>https://{Claim:loadUri}</LoadUri>)时,触发错误:
Invalid URI: The hostname could not be parsed.
现寻求在ContentDefinition中使用完整动态URI的可行方案。
解决方案
方案1:静态代理页面跳转
在Azure Blob Storage部署一个通用代理HTML页面,通过JavaScript读取传递的动态URI参数并跳转:
- 固定ContentDefinition的
<LoadUri>为代理页面地址,同时将动态loadUri作为查询参数传入:
<ContentDefinition Id="api.signuporsignin"> <LoadUri>https://your-static-blob-host/proxy.html?target={Claim:loadUri}</LoadUri> <RecoveryUri>~/common/default_page_error.html</RecoveryUri> <DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.5</DataUri> <Metadata> <Item Key="DisplayName">Signin and Signup</Item> </Metadata> </ContentDefinition>
- 代理页面核心逻辑示例:
<script> window.onload = () => { const params = new URLSearchParams(window.location.search); const target = params.get('target'); if (target) { try { new URL(target); window.location.replace(target); } catch (err) { window.location.replace('~/common/default_page_error.html'); } } else { window.location.replace('~/common/default_page_error.html'); } }; </script>
方案2:拆分URI声明拼接
通过ClaimsTransformation将完整loadUri拆分为协议、主机、路径三个独立声明,再在ContentDefinition中拼接:
- 定义URI拆分转换:
<ClaimsTransformation Id="SplitLoadUri" TransformationMethod="ParseUri"> <InputClaims> <InputClaim ClaimTypeReferenceId="loadUri" TransformationClaimType="inputUri" /> </InputClaims> <OutputClaims> <OutputClaim ClaimTypeReferenceId="uriScheme" TransformationClaimType="scheme" /> <OutputClaim ClaimTypeReferenceId="uriHost" TransformationClaimType="host" /> <OutputClaim ClaimTypeReferenceId="uriPath" TransformationClaimType="path" /> </OutputClaims> </ClaimsTransformation>
- 在用户旅程中调用该转换:
<OrchestrationStep Order="2" Type="ClaimsExchange"> <ClaimsExchanges> <ClaimsExchange Id="SplitUriExchange" TechnicalProfileReferenceId="SplitLoadUriProfile" /> </ClaimsExchanges> </OrchestrationStep>
- 配置ContentDefinition使用拆分后的声明拼接URI:
<ContentDefinition Id="api.signuporsignin"> <LoadUri>{Claim:uriScheme}://{Claim:uriHost}{Claim:uriPath}</LoadUri> <RecoveryUri>~/common/default_page_error.html</RecoveryUri> <DataUri>urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.5</DataUri> <Metadata> <Item Key="DisplayName">Signin and Signup</Item> </Metadata> </ContentDefinition>
方案3:预注册可信主机名
若业务涉及的Blob主机名有限,可将主机名预添加到B2C可信域名列表,调整API仅返回路径部分,再拼接固定协议+主机名:
<ContentDefinition Id="api.signuporsignin"> <LoadUri>https://{Claim:uriHost}{Claim:uriPath}</LoadUri> <!-- 其他配置 --> </ContentDefinition>
内容的提问来源于stack exchange,提问作者Guilherme Luiz

