[AEM Forms]{class="badge positive" title="适用于AEM Forms)。"}
在应用程序中集成关联UI
交互式通信功能在早期采用者计划下可用。 将工作地址中的电子邮件发送至aem-forms-ea@adobe.com以请求访问权限。
本文说明如何将关联UI与您的应用程序集成,从而使面向客户的专业人员(如现场助理和服务代理)能够在Publish实例上实时生成个性化的交互式通信。
先决条件
在将关联UI与您的应用程序集成之前,请确保您已:
- 交互式通信已创建和发布
- 已启用弹出窗口支持的浏览器
- 关联用户必须属于Forms-associates组
- 使用AEM支持的任何身份验证机制(例如SAML 2.0、OAuth或自定义身份验证处理程序)配置的身份验证
- 本文演示了将SAML 2.0和Microsoft Entra ID (Azure AD)用作身份提供程序的身份验证配置。
- 对于关联UI,需要除SAML 2.0身份验证文章中说明的标准设置之外的其他SAML配置。 有关详细信息,请参阅关联UI的其他SAML配置部分。
关联UI的其他SAML配置
为关联UI配置SAML 2.0身份验证时,必须在OSGi配置文件中应用以下特定设置。
SAML身份验证处理程序
SAML身份验证处理程序是一个OSGi工厂配置,它允许为不同的资源树使用多个SAML配置。 这支持多站点AEM部署,并允许您向现有SAML设置添加关联UI资源。
在com.adobe.granite.auth.saml.SamlAuthenticationHandler~saml.cfg.json中创建文件ui.config/src/main/content/jcr_root/apps/<project-name>/osgiconfig/config.publish:
{
"path": ["/libs/fd/associate"],
"serviceProviderEntityId": "https://publish-p{program-id}-e{env-id}.adobeaemcloud.com",
"assertionConsumerServiceURL": "https://publish-p{program-id}-e{env-id}.adobeaemcloud.com/libs/fd/associate/saml_login"
"idpUrl": "https://login.microsoftonline.com/{azure-tenant-id}/saml2",
"idpCertAlias": "{your-certificate-alias}",
"idpIdentifier": "https://sts.windows.net/{azure-tenant-id}/",
"userIDAttribute": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
"createUser": true,
"userIntermediatePath": "saml",
"synchronizeAttributes": [
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname=profile/givenName",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname=profile/familyName",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress=profile/email"
],
"addGroupMemberships": true,
"defaultGroups": ["forms-associates"],
"defaultRedirectUrl": "/libs/fd/associate/ui.html",
"idpHttpRedirect": false,
"service.ranking": 5002
}
path/libs/fd/associatedefaultGroupsforms-associates以自动将用户分配给所需的组defaultRedirectUrlidpHttpRedirectfalseidpCertAliasSling身份验证程序
Sling Authenticator强制进行身份验证以访问发布上的关联UI资源。
更新org.apache.sling.engine.impl.auth.SlingAuthenticator~saml.cfg.json中的文件ui.config/src/main/content/jcr_root/apps/<project-name>/osgiconfig/config.publish:
{
"sling.auth.requirements": ["+/libs/fd/associate/ui.html"],
"sling.auth.anonymous": false
}
Dispatcher筛选器
添加以下规则以确保Interactive Communications API和关联UI在发布实例上正确运行。
如果尚未存在,请将以下规则添加到您的dispatcher/src/conf.dispatcher.d/filters/filters.any文件:
# Allow Interactive Communications APIs and Associate UI
/XXXX { /type "allow" /method '(GET|OPTIONS)' /url "/adobe/communications" }
/XXXX { /type "allow" /method '(GET|POST|OPTIONS)' /url "/adobe/communications/*" }
/XXXX { /type "allow" /method "GET" /url "/content/dam/fd:fonts/*" }
/XXXX { /type "allow" /method '(GET|OPTIONS)' /url "/libs/fd/associate/*" }
XXXX替换为现有filters.any文件中使用的相应数字序列。在发布实例上调用关联UI
本节将指导您从自己的应用程序中启动关联UI。 按照以下步骤快速入门 — 从现成的示例HTML页面开始,然后为您的环境配置它。
步骤1:开始创建示例HTML页面
要快速测试和了解关联UI集成的工作方式,请使用以下示例HTML页面。 将此代码复制到HTML文件中,并在浏览器中将其打开。
HTML示例提供了一个简单的表单界面,您可以在其中输入交互式通信详细信息,然后单击以启动关联UI。
<!DOCTYPE html>
<html>
<head>
<title>Associate UI Integration</title>
<style>
body {
font-family: sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
}
.form-group {
margin: 20px 0;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input, textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
textarea {
height: 80px;
font-family: monospace;
}
button {
padding: 10px 20px;
margin: 5px;
cursor: pointer;
border-radius: 4px;
}
.btn-primary {
background: #007bff;
color: white;
border: none;
}
.btn-primary:hover {
background: #0056b3;
}
.error {
color: red;
font-size: 12px;
display: none;
}
</style>
</head>
<body>
<h1>Launch Associate UI</h1>
<form id="form">
<div class="form-group">
<label>IC ID *</label>
<input type="text" id="icId" placeholder="Enter Interactive Communication ID" required>
</div>
<div class="form-group">
<label>Prefill Service</label>
<input type="text" id="serviceName" placeholder="e.g., CustomerDataService">
</div>
<div class="form-group">
<label>Service Parameters (JSON)</label>
<textarea id="serviceParams" placeholder='{"customerId": "12345"}'>{}</textarea>
<span id="paramsError" class="error">Invalid JSON format</span>
</div>
<div class="form-group">
<label>Options (JSON)</label>
<textarea id="options" placeholder='{"mode": "edit", "locale": "en_US"}'>{}</textarea>
<span id="optionsError" class="error">Invalid JSON format</span>
</div>
<button type="button" onclick="reset()">Reset</button>
<button type="button" class="btn-primary" onclick="launch()">Launch Associate UI</button>
</form>
<script>
// Replace with your AEM Publish instance URL
const AEM_URL = 'https://publish-p{program-id}-e{env-id}.adobeaemcloud.com/libs/fd/associate/ui.html';
function validateJSON(str, errorId) {
const err = document.getElementById(errorId);
try {
const obj = JSON.parse(str || '{}');
err.style.display = 'none';
return obj;
} catch (e) {
err.style.display = 'block';
return null;
}
}
function launch() {
const icId = document.getElementById('icId').value.trim();
if (!icId) {
alert('IC ID is required');
return;
}
const params = validateJSON(document.getElementById('serviceParams').value, 'paramsError');
const opts = validateJSON(document.getElementById('options').value, 'optionsError');
if (!params || !opts) {
alert('Please fix JSON errors before launching');
return;
}
const data = {
id: icId,
prefill: {
serviceName: document.getElementById('serviceName').value.trim(),
serviceParams: params
},
options: opts
};
const win = window.open(AEM_URL, '_blank');
if (!win) {
alert('Pop-up blocked. Please enable pop-ups for this site.');
return;
}
const handler = (e) => {
if (e.data && e.data.type === 'READY' && e.data.source === 'APP') {
win.postMessage({ type: 'INIT', source: 'PORTAL', data }, '*');
window.removeEventListener('message', handler);
}
};
window.addEventListener('message', handler);
// Fallback timeout in case READY message is missed
setTimeout(() => {
if (win && !win.closed) {
win.postMessage({ type: 'INIT', source: 'PORTAL', data }, '*');
window.removeEventListener('message', handler);
}
}, 1000);
}
function reset() {
document.getElementById('form').reset();
document.getElementById('serviceParams').value = '{}';
document.getElementById('options').value = '{}';
document.getElementById('paramsError').style.display = 'none';
document.getElementById('optionsError').style.display = 'none';
}
</script>
</body>
</html>
步骤2:配置发布实例URL
在启动关联UI之前,您需要将示例指向AEM Forms Cloud Service发布实例。
在上面的HTML示例中,在<script>部分中找到以下行:
const AEM_URL = 'https://publish-p{program-id}-e{env-id}.adobeaemcloud.com/libs/fd/associate/ui.html';
将占位符值替换为您的实际环境详细信息:
{program-id}:您的AEM Cloud Service项目ID{env-id}:您的环境ID
例如,如果您的项目ID为12345,环境ID为67890,则URL将变为:
const AEM_URL = 'https://publish-p12345`-e67890.adobeaemcloud.com/libs/fd/associate/ui.html';
postMessage API安全传递的。步骤3:了解JavaScript集成功能
示例HTML使用以下JavaScript函数来启动关联UI。 此函数验证IC ID、构造数据有效负载、在新的浏览器窗口中打开关联UI,并使用浏览器的postMessage API发送数据。
function launchAssociateUI(icId, prefillService, prefillParams, options) {
if (!icId) {
console.error('IC ID required');
return;
}
const data = {
id: icId,
prefill: {
serviceName: prefillService || '',
serviceParams: prefillParams || {}
},
options: options || {}
};
const AEM_URL = 'https://your-aem.adobeaemcloud.com/libs/fd/associate/ui.html';
const win = window.open(AEM_URL, '_blank');
if (!win) {
alert('Please enable pop-ups for this site');
return;
}
const readyHandler = (event) => {
if (event.data && event.data.type === 'READY' && event.data.source === 'APP') {
win.postMessage({ type: 'INIT', source: 'PORTAL', data: data }, '*');
window.removeEventListener('message', readyHandler);
}
};
window.addEventListener('message', readyHandler);
// Fallback timeout in case READY message is missed
setTimeout(() => {
if (win && !win.closed) {
win.postMessage({ type: 'INIT', source: 'PORTAL', data: data }, '*');
window.removeEventListener('message', readyHandler);
}
}, 1000);
}
该函数接受四个参数:IC ID(必需)、预填充服务名称、预填充服务参数和其他选项。 这些参数将结构化到数据有效负载中,如下所述。
步骤4:了解数据有效载荷结构
有效负载格式:
const data = {
id: "your-ic-id", // Required: Interactive Communication ID
prefill: { // Optional: Data to prefill the IC
serviceName: "YourService",
serviceParams: { key: "value" }
},
options: {} // Optional: Additional configuration options
};
有效负载组件:
idprefillprefill.serviceNameprefill.serviceParamsoptions数据有效负载示例
最小有效负载(仅限IC ID)
当不需要预填充数据时,使用此项:
{
"id": "12345",
"prefill": {
"serviceName": "",
"serviceParams": {}
},
"options": {}
}
包含预填充数据
使用它动态地向IC填充客户数据:
{
"id": "12345",
"prefill": {
"serviceName": "IC_FDM",
"serviceParams": {
"customerId": "101",
"accountNumber": "ACC-98765"
}
},
"options": {}
}
具有PDF渲染选项
使用此选项可指定其他渲染选项:
{
"id": "12345",
"prefill": {
"serviceName": "IC_FDM",
"serviceParams": {
"customerId": "101",
"accountNumber": "ACC-98765"
}
},
"options": {
"locale": "en_US",
"includeAttachments": "true",
"webOptimized": "false",
"embedFonts": "false",
"makeAccessible": "false"
}
}
步骤5:输入IC ID并启动关联UI
现在,您可以使用示例HTML页面启动关联UI:
-
输入IC ID:在 IC ID 字段中,输入已发布的交互式通信的标识符。 这是唯一的必填字段。
-
配置预填充服务:如果要使用动态数据预填充IC,请在 预填充服务 字段中输入表单数据模型服务名称。 例如,使用
FdmTestData作为示例数据。
-
单击“启动关联UI”:单击“启动关联UI”按钮。 此时将打开一个新浏览器窗口,其中显示与交互式通信预先加载的关联UI 。
输入数据,此时将显示关联UI,如下所示:
疑难解答
已阻止弹出窗口
问题:“关联UI”窗口未打开。
解决方案:
- 在浏览器设置中为域启用弹出窗口
- 确保从用户操作(例如,按钮单击)中调用
window.open() - 使用不同的浏览器测试以识别阻止行为
数据未加载
问题:交互式通信打开,但数据未填充。
解决方案:
- 验证IC ID是否正确,以及IC是否已发布
- 检查浏览器控制台是否显示 JavaScript 错误
- 确保
postMessage结构与规范完全匹配 - 验证表单数据模型服务是否已正确配置
身份验证错误
问题:打开关联UI时,用户收到身份验证错误。
解决方案:
- 在发布实例上配置SAML 2.0身份验证
- 验证用户是否属于 forms-associates 组
- 检查会话超时设置
CORS错误
问题:控制台中存在跨源资源共享错误。
解决方案:
- 对于开发:在
'*'中使用postMessage作为目标来源 - 用于生产:指定应用程序的确切起源URL
- 确保发布实例CORS设置允许您的应用程序域