教程:使用防病毒软件扫描文件附件
[AEM 表单]{class="badge positive" title="适用于AEM Forms"}
文件附件病毒扫描程序/验证程序功能在早期采用程序程序下。 您可以使用官方电子邮件 ID 写信给 aem-forms-ea@adobe.com,加入早期采用者计划并申请使用该功能。
本教程将带您一个接一个地学习。 您将运行ClamAV防病毒引擎,向AEM添加一个自定义验证器,使用file-upload字段创建一个示例自适应表单,连接验证器,并确认感染病毒的文件在提交时已被拒绝。 即使您是AEM的新用户,也会按照此说明进行操作。 您需要的每个命令、屏幕路径和值都会拼写出来。
有关验证器和接口引用背后的概念,请参阅随附文章使用自定义验证器在Adaptive Forms中扫描文件附件。 完成本教程不需要先阅读它,但它解释了为什么每一条都存在。
您将构建什么 what-you-will-build
到最后,您将拥有:
- 正在运行的ClamAV守护程序(
clamd),可根据请求扫描文件。 - 自定义AEM服务(ClamAV扫描程序),用于将每个上传的文件发送到
clamd并拒绝受感染的文件。 - 名为 文件附件扫描程序演示 的自适应表单示例,带有文件上传字段和提交按钮。
- 正在运行的测试:已成功提交普通文件,并且已阻止已知的测试病毒文件。
开始之前:假设和先决条件 assumptions
本教程假定采用以下设置。 如果缺少任何项目,请在启动之前安装或获取它。 每个项目都包括如何对其进行检查。
http://localhost:4502上访问http://localhost:4502。 您应该会看到AEM登录或“开始”屏幕。http://localhost:4502登录(默认的本地凭据为admin / admin)FT_FORMS-23497FileAttachmentValidatorManager功能。 提交选项卡字段本身就是本教程在步骤7中添加的内容。 无论哪种方式,它都不是现成可用的。ui.apps模块中拥有或可以创建自适应表单容器代理组件java -versionmvn -versiondocker --versioncom.adobe.forms.common.service界面的早期访问依赖项aem-forms-addon-sdk-<version>.zip(需要早期采用者计划权利)要替换的值 substitute-values
无论在何处看到这些占位符,都请将其替换为您自己的值:
<PROJECT_ROOT>:您的AEM Maven项目的文件夹。<APP_ID>:项目的应用程序ID或捆绑包模块名称(例如,mysite)。<SDK_DEPENDENCY_VERSION>:在您下载的SDK中捆绑的adobe-xfaforms-common版本(组id和工件id已修复;请参阅步骤3)。
路线图 roadmap
您可以按顺序完成这些步骤:
- 启动ClamAV后台程序(
clamd)。 - 设置一个AEM Maven项目(如果您已经有一个项目,则跳过)。
- 添加早期访问依赖关系。
- 添加ClamAV验证器类。
- 构建并部署到AEM。
- 在AEM中配置
clamd连接。 - 将验证器字段添加到表单对话框。
- 创建自适应表单示例。
- 将ClamAV扫描仪连接到窗体。
- 使用干净的文件和测试病毒文件进行测试。
步骤1:启动ClamAV守护程序 step-1-clamd
ClamAV作为名为clamd的后台服务运行。 您构建的验证器将每个上载的文件流式传输到clamd,后者会回复OK以获取干净的文件,或者在检测到威胁名称时报告威胁名称。
运行clamd的最快方法是Docker。
-
启动ClamAV:
code language-none docker run -d --name clamav -p 3310:3310 clamav/clamav:latestnote NOTE 在Apple Silicon (arm64) Mac上,此图像没有本机arm64内部版本,并且上述命令因 no matching manifest for linux/arm64/v8而失败。 添加--platform linux/amd64以改为在模拟下运行:code language-none docker run -d --name clamav --platform linux/amd64 -p 3310:3310 clamav/clamav:latest -
等待它准备就绪。 第一次启动时,它会下载病毒数据库,这可能需要几分钟的时间。 在数据库已加载且
clamd正在侦听之前,请观察日志:code language-none docker logs -f clamav按
Ctrl+C可在日志准备就绪后停止关注日志。 -
验证是否可以在端口
3310上访问clamd:code language-none printf 'PING\n' | nc localhost 3310预期结果:响应为
PONG。
clamd.conf中的端口3310上启用clamd守护程序和TCP套接字,使用freshclam更新数据库,然后启动clamd。 然后,在上面的步骤3中运行验证。clamd作为自己的进程运行,独立于AEM。 此本地设置用于开发。 在AEM as a Cloud Service上,您无法在AEM主机上运行clamd,因此在实际环境中,您要将它作为并存服务或外部服务运行,并将验证器指向它。 希望在同一区域有一个位于同一位置的实例,以将文件内容保留在您的环境中,以实现数据驻留和法规遵从性。步骤2:设置AEM Maven项目 step-2-project
自定义Java代码将作为Maven项目构建的捆绑包部署到AEM。 如果您已有AEM项目,请跳至步骤3并使用其捆绑包模块(通常名为core)。
如果您没有项目原型,请使用AEM项目原型创建一个项目:
-
在终端中,转到保存代码的文件夹并运行原型。 将
<APP_ID>替换为短小写名称,如mysite:code language-none mvn -B org.apache.maven.plugins:maven-archetype-plugin:generate -D archetypeGroupId=com.adobe.aem -D archetypeArtifactId=aem-project-archetype -D archetypeVersion=LATEST -D appId=<APP_ID> -D appTitle="<APP_ID>" -D name="<APP_ID>" -D groupId=com.example -D artifactId=<APP_ID> -D aemVersion=cloud预期结果:包含包括
core、ui.apps和all的模块的新文件夹<APP_ID>(这是您的<PROJECT_ROOT>)。 -
您稍后添加的Java代码将放入
core模块中的:code language-none <PROJECT_ROOT>/core/src/main/java/
core模块。步骤3:添加早期访问依赖关系 step-3-dependency
您的代码针对来自com.adobe.forms.foundation:adobe-xfaforms-common的FileAttachmentValidator接口进行编译(假设#9)。 此依赖项未发布到公共Maven存储库。 它捆绑在AEM Forms附加组件SDK中,因此您可以从其中提取它并将其安装到本地Maven存储库中。
-
从Adobe软件分发门户下载
aem-forms-addon-sdk-<version>.zip的最新可用内部版本(需要早期采用者计划权利)。 始终使用最新版本;以前的版本可能尚未包含此依赖关系。 -
提取依赖项jar。 SDK zip包含功能存档(
.far),并且该jar捆绑在其中:code language-none unzip -p aem-forms-addon-sdk-<version>.zip aem-forms-addon-<version>.far > addon.far unzip -l addon.far | grep adobe-xfaforms-common第二个命令显示下载中捆绑的准确jar路径和版本,例如
com/adobe/forms/foundation/adobe-xfaforms-common/<version>/adobe-xfaforms-common-<version>.jar。 在下一步中使用该路径和版本。code language-none unzip -p addon.far "com/adobe/forms/foundation/adobe-xfaforms-common/<version>/adobe-xfaforms-common-<version>.jar" > adobe-xfaforms-common.jar -
将提取的jar安装到本地Maven存储库中,以便
pom.xml可以解析它。 包括-DgeneratePom=true: jar嵌入了其内部Adobe生成POM,其中包含您的项目无法解析的父引用,并且此标记将其替换为干净的自包含标记:code language-none mvn install:install-file -Dfile=adobe-xfaforms-common.jar -DgroupId=com.adobe.forms.foundation -DartifactId=adobe-xfaforms-common -Dversion=<version> -Dpackaging=jar -DgeneratePom=true -
打开
<PROJECT_ROOT>/core/pom.xml。 -
在
<dependencies>部分中,使用您刚刚安装的相同版本添加依赖项。 使用provided作用域,因为该接口由AEM在运行时提供:code language-xml <dependency> <groupId>com.adobe.forms.foundation</groupId> <artifactId>adobe-xfaforms-common</artifactId> <version><SDK_DEPENDENCY_VERSION></version> <scope>provided</scope> </dependency> -
保存文件。
步骤4:添加ClamAV验证器类 step-4-class
-
在以下位置创建新文件:
code language-none <PROJECT_ROOT>/core/src/main/java/com/example/forms/security/ClamAVFileAttachmentValidator.java创建
forms/security文件夹(如果不存在)。 您可以使用自己的包名称。 如果是,请更改package行以匹配。 -
粘贴以下代码:
code language-java package com.example.forms.security; import com.adobe.forms.common.service.FileAttachmentValidator; import com.adobe.forms.common.service.FileAttachmentValidationResult; import com.adobe.forms.common.service.FileAttachmentWrapper; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.metatype.annotations.AttributeDefinition; import org.osgi.service.metatype.annotations.Designate; import org.osgi.service.metatype.annotations.ObjectClassDefinition; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.StandardCharsets; @Component(service = FileAttachmentValidator.class) @Designate(ocd = ClamAVFileAttachmentValidator.Config.class) public class ClamAVFileAttachmentValidator implements FileAttachmentValidator { @ObjectClassDefinition(name = "ClamAV File Attachment Scanner") public @interface Config { @AttributeDefinition(name = "clamd Host") String clamd_host() default "localhost"; @AttributeDefinition(name = "clamd Port") int clamd_port() default 3310; @AttributeDefinition(name = "Scan Timeout (ms)") int clamd_timeout() default 30000; } private static final String VALIDATOR_NAME = "ClamAV Scanner"; private static final int CHUNK_SIZE = 8192; private String host; private int port; private int timeout; @Activate protected void activate(Config config) { this.host = config.clamd_host(); this.port = config.clamd_port(); this.timeout = config.clamd_timeout(); } @Override public FileAttachmentValidationResult validateFileAttachment(FileAttachmentWrapper wrapper) { if (wrapper == null) { return new FileAttachmentValidationResult(false, "No attachment was received.", wrapper); } byte[] content = wrapper.getValue(); if (content == null || content.length == 0) { return new FileAttachmentValidationResult(false, "The attached file is empty.", wrapper); } try { String response = scan(content); if (response.endsWith("OK")) { return new FileAttachmentValidationResult(true, "File passed the virus scan.", wrapper); } if (response.contains("FOUND")) { return new FileAttachmentValidationResult(false, "A virus was detected in the attached file. Upload was rejected.", wrapper); } return new FileAttachmentValidationResult(false, "The file could not be scanned. Please try again later.", wrapper); } catch (Exception e) { // Fail closed: reject when clamd is unreachable rather than accept an unscanned file. return new FileAttachmentValidationResult(false, "The virus scanner is unavailable. Please try again later.", wrapper); } } /** * Streams the file to clamd using the INSTREAM command and returns the daemon's response. */ private String scan(byte[] data) throws Exception { try (Socket socket = new Socket()) { socket.connect(new InetSocketAddress(host, port), timeout); socket.setSoTimeout(timeout); try (OutputStream raw = socket.getOutputStream(); DataOutputStream out = new DataOutputStream(raw); InputStream in = socket.getInputStream()) { out.writeBytes("zINSTREAM\0"); for (int offset = 0; offset < data.length; offset += CHUNK_SIZE) { int len = Math.min(CHUNK_SIZE, data.length - offset); out.writeInt(len); out.write(data, offset, len); } out.writeInt(0); // zero-length chunk signals end of stream out.flush(); ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream(); byte[] buffer = new byte[512]; int read; while ((read = in.read(buffer)) != -1) { responseBuffer.write(buffer, 0, read); } return responseBuffer.toString(StandardCharsets.US_ASCII.name()).trim(); } } } @Override public String getFileAttachmentValidatorName() { return VALIDATOR_NAME; } } -
保存文件。
步骤5:构建并部署到AEM step-5-deploy
-
运行AEM(假设#1)后,从项目根目录进行生成和部署。 此命令将捆绑包安装到本地创作实例上:
code language-none cd <PROJECT_ROOT> mvn clean install -PautoInstallBundle预期结果:生成以
BUILD SUCCESS结尾。 -
确认服务正在运行。 打开组件控制台:
code language-none http://localhost:4502/system/console/components此页面没有内置搜索框:列出了5,000多个组件,请使用浏览器自己的页面查找功能(Cmd+F或Ctrl+F)并搜索
ClamAVFileAttachmentValidator。预期结果:组件已列出,其状态为活动 (或已满足)。 如果不满意,请参阅故障排除。
步骤6:配置clad连接 step-6-config
告知验证器clamd的位置。 对于本地开发,默认值(localhost:3310)已经与步骤1匹配,因此仅当值不同时才需要此步骤。 执行一次以确认设置存在。
-
打开配置控制台:
code language-none http://localhost:4502/system/console/configMgr -
此页面也没有内置搜索框:使用浏览器的 ClamAV文件附件扫描程序 的页面内查找(Cmd+F或Ctrl+F)并打开它。
-
确认或设置:
table 0-row-2 1-row-2 2-row-2 3-row-2 设置 本教程的值 Clamd主机 localhost固网端口 3310扫描超时(毫秒) 30000OSGi配置控制台中的
-
选择保存。
.cfg.json文件),以便它们随每个部署一起移动,而不是手动设置。步骤7:将验证器字段添加到表单对话框 step-7-dialog-field
现成的自适应表单容器对话框中不存在 文件附件病毒扫描程序/验证器 字段。 对于基于核心组件的表单,可在自己的项目中添加一次。 这是一个一次性步骤;如果以后添加更多验证器,则不要重复此步骤。
-
如果您的
formcontainer代理组件不存在,请在以下位置创建它:code language-none <PROJECT_ROOT>/ui.apps/src/main/content/jcr_root/apps/<APP_ID>/components/adaptiveForm/formcontainer/.content.xmlcode language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" jcr:primaryType="cq:Component" jcr:title="Form Container" sling:resourceSuperType="core/fd/components/form/container/v2/container"/>如果您已经拥有此组件(大多数项目都是从核心组件原型创建的),请跳至下一步。
-
在下列位置创建一个对话框扩展:
code language-none <PROJECT_ROOT>/ui.apps/src/main/content/jcr_root/apps/<APP_ID>/components/adaptiveForm/formcontainer/_cq_dialog/.content.xmlcode language-xml <?xml version="1.0" encoding="UTF-8"?> <jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:sling="http://sling.apache.org/jcr/sling/1.0" jcr:primaryType="nt:unstructured"> <content jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <tabs jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <submitActions jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <columns jcr:primaryType="nt:unstructured"> <items jcr:primaryType="nt:unstructured"> <fileAttachmentValidator jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/form/select" fieldLabel="File Attachment Virus Scanner/Validator" fieldDescription="Select a registered validator configuration to scan submitted file attachments. Select None to disable validation for this form." emptyText="None" name="./fileAttachmentValidator"> <datasource jcr:primaryType="nt:unstructured" sling:resourceType="<APP_ID>/datasources/fileattachmentvalidators"/> </fileAttachmentValidator> </items> </columns> </items> </submitActions> </items> </tabs> </items> </content> </jcr:root>这仅定义一个新字段,将真实对话框的节点名称镜像到插入点。 它不会重新定义或替换任何现有的提交选项卡字段。 请参阅配套文章中的将验证器字段添加到表单对话框,以了解其工作原理。
-
添加列出已注册验证器的数据源servlet。 无论您使用哪个验证器引擎,该字段都是相同的;请参阅将验证器字段添加到伴随文章中的表单对话框,以了解其功能和原因。 创建时间:
code language-none <PROJECT_ROOT>/core/src/main/java/com/example/forms/security/FileAttachmentValidatorDataSourceServlet.javacode language-java package com.example.forms.security; import com.adobe.forms.common.service.FileAttachmentValidator; import com.adobe.forms.common.service.FileAttachmentValidatorManager; import com.adobe.granite.ui.components.ds.DataSource; import com.adobe.granite.ui.components.ds.SimpleDataSource; import com.adobe.granite.ui.components.ds.ValueMapResource; import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.SlingHttpServletResponse; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceMetadata; import org.apache.sling.api.servlets.HttpConstants; import org.apache.sling.api.servlets.SlingSafeMethodsServlet; import org.apache.sling.api.wrappers.ValueMapDecorator; import org.apache.sling.servlets.annotations.SlingServletResourceTypes; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicy; import javax.servlet.Servlet; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Component(service = { Servlet.class }) @SlingServletResourceTypes( resourceTypes = "<APP_ID>/datasources/fileattachmentvalidators", methods = HttpConstants.METHOD_GET) public class FileAttachmentValidatorDataSourceServlet extends SlingSafeMethodsServlet { @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) private volatile FileAttachmentValidatorManager fileAttachmentValidatorManager; @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) { List<Resource> options = new ArrayList<>(); FileAttachmentValidatorManager manager = fileAttachmentValidatorManager; if (manager != null) { List<FileAttachmentValidator> validators = manager.getValidators(); if (validators != null) { for (FileAttachmentValidator validator : validators) { String name = validator.getFileAttachmentValidatorName(); if (name != null && !name.isEmpty()) { options.add(createOption(request, name)); } } } } DataSource dataSource = new SimpleDataSource(options.iterator()); request.setAttribute(DataSource.class.getName(), dataSource); } private Resource createOption(SlingHttpServletRequest request, String name) { Map<String, Object> props = new HashMap<>(); props.put("value", name); props.put("text", name); return new ValueMapResource(request.getResourceResolver(), new ResourceMetadata(), "nt:unstructured", new ValueMapDecorator(props)); } }将对话框XML和Servlet的
resourceTypes中的<APP_ID>替换为项目的实际应用程序ID(匹配假设#4),如果包名称与步骤4不同,请调整包名称。 -
生成和部署这两个更改。 您更改了内容(对话框)和代码(servlet),因此同时使用这两个配置文件:仅
autoInstallPackage部署内容并保留servlet的捆绑包未重新部署。code language-none cd <PROJECT_ROOT> mvn clean install -PautoInstallPackage,autoInstallBundle预期结果:生成以
BUILD SUCCESS结尾,并且同时安装了ui.apps内容包(包括此对话框更改)和core捆绑包(包括新的servlet)。
FileAttachmentValidator都会自动显示在下拉列表中,因为每个表单都有自己的getFileAttachmentValidatorName(),并且emptyText="None"将保留“无验证器”作为默认值,以便在您明确选择一个现有表单之前,该表单不会受到影响。步骤8:创建自适应表单示例 step-8-form
现在,创建一个包含file-upload字段的简单表单。
-
打开Forms和文档:
code language-none http://localhost:4502/aem/forms.html/content/dam/formsanddocuments -
选择创建(右上方),然后选择自适应表单。
-
从图库中选择模板。 基础不是单独的问题:它是您选择的模板的一部分,在每个模板的名称(例如,自适应表单(核心组件))下显示为小字幕。
note important IMPORTANT 多个模板全名为空白表单:一个用于核心组件,一个用于基础组件,一个用于Edge Delivery Services。 选错一个很容易出错,并且会以静默方式失败:本教程的其余部分似乎仍然有效,但从未调用文件附件病毒扫描程序/验证器字段,因为该管道仅存在于基于核心组件的表单中。 在继续之前,请确认子标题是否为自适应表单(核心组件)。 -
在 属性 中,设置:
- 标题:
File Attachment Scanner Demo - 主题:选择任何可用的主题(例如,画布)
然后选择创建。
- 标题:
-
在确认对话框中,选择 打开 以在编辑器中打开表单。
预期结果:自适应表单编辑器打开时表单为空。
-
添加file-upload字段:
- 打开 组件 浏览器(左边栏中的组件图标,或者选择空表单区域并选择“插入组件”选项)。
- 找到 文件附件 组件并将其拖动到表单上。
-
添加提交按钮:
- 从同一组件浏览器中,将 自适应表单按钮 拖动到表单上“文件”字段下方。
- 选择按钮,打开其属性(扳手图标),将其 按钮类型 设置为提交,然后进行确认。
-
保存表单。 编辑器会自动保存,但您可以通过退出编辑器来强制进行保存。
预期结果:表单现在具有文件附件字段和提交按钮。
步骤9:将ClamAV扫描仪连接到窗体 step-9-connect
-
在表单编辑器中,选择指南容器 (最外部的容器)以打开 自适应表单容器 属性。 使用属性(扳手)图标。
-
打开 提交 选项卡。
-
找到 文件附件病毒扫描程序/验证器 下拉列表,然后选择ClamAV扫描程序。
此字段及其选项列表来自步骤7:已部署到您自己的项目的对话框扩展和数据源servlet。 条目是您的代码中由
getFileAttachmentValidatorName()返回的名称。 如果您更改了VALIDATOR_NAME,请改为选择该名称。note important IMPORTANT 如果此字段完全缺失,则说明您尚未完成步骤7,或者未部署步骤7中的 ui.apps包。 对于基于核心组件的表单,此字段绝不会现成显示。 -
选择完成,然后保存表单。
在“文件附件病毒扫描程序/验证器”字段中选择ClamAV扫描程序的“自适应表单容器”对话框的
步骤10:测试集成 step-10-test
测试这两个结果。
测试A:接受干净的文件 test-clean
-
打开表单的预览:
code language-none http://localhost:4502/content/dam/formsanddocuments/file-attachment-scanner-demo/jcr:content?wcmmode=disabled如果表单的路径不同,请从“Forms和文档”中打开它,然后选择预览。
-
附加普通PDF或图像,然后选择提交。
预期结果:已成功提交表单。
测试B:已阻止测试病毒 test-virus
-
创建一个名为
eicar.txt的纯文本文件,其唯一内容是标准EICAR防病毒测试字符串。 这是每个防病毒引擎都会主动检测的无害文件:code language-none X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*您也可以从eicar.org下载它。
-
在表单中附加
eicar.txt并选择提交。预期结果:提交被阻止。 拒绝的显示方式因表单配置的 提交操作 而异:标准的感谢页面流程通常在文件字段上显示内联错误,而提交到REST端点(本教程的示例表单使用此项)倾向于显示通用的提交失败消息,而不是字段级消息。 无论如何,表单都不会提交。
-
确认验证器实际运行并拒绝了该文件。 查看AEM错误日志,无论故障是如何在浏览器中显示的,该日志都是查看所发生情况的可靠方法:
code language-none <AEM_SDK_FOLDER>/crx-quickstart/logs/error.log查找来自验证器的拒绝消息(例如,
A virus was detected in the attached file)。
疑难解答 troubleshooting
docker run失败,错误为no matching manifest for linux/arm64/v8。 您使用的是Apple Silicon Mac;clamav/clamav图像没有本机arm64内部版本。 将--platform linux/amd64添加到步骤1中的命令。
PONG未在步骤1.中返回 clamd未就绪或端口未发布。 检查docker logs clamav是否完成数据库加载,并确认容器映射端口3310 (docker ps)。
步骤2的原型命令因Unsupported class file major version...而失败。 您的默认java/mvn正在比允许使用的假设更新#5JDK上运行:原型的生成后脚本无法解析来自21以上的Java版本的类文件。 将JAVA_HOME指向Java 11或21安装,然后重新运行该命令。 如果第一次尝试已部分生成项目(模块文件夹不匹配,缺少文件),请在重试之前删除该输出目录,而不是就地重新运行。
项目未编译(找不到FileAttachmentValidator)。 早期访问依赖项(步骤3)缺失、未安装到本地Maven存储库或pom.xml的版本与安装的jar不匹配。 使用unzip -l addon.far | grep adobe-xfaforms-common重新检查版本。
步骤5.中未满足组件 打开http://localhost:4502/system/console/components,找到ClamAVFileAttachmentValidator,然后阅读原因。 缺少接口通常意味着运行时不存在依赖关系。 确认您的AEM环境具有抢先访问功能。
文件附件病毒扫描程序/验证程序字段完全不显示在“提交”选项卡中(步骤9)。 确认实际部署了步骤7 ui.apps包(对话框扩展和数据源servlet)。 检查http://localhost:4502/system/console/components以了解FileAttachmentValidatorDataSourceServlet。 此外,请确认已为您的程序启用FT_FORMS-23497功能切换;它可审核数据源依赖的基础FileAttachmentValidatorManager功能。
出现该字段,但ClamAV扫描仪不在下拉列表中(步骤9)。 确认ClamAVFileAttachmentValidator组件处于活动状态,getFileAttachmentValidatorName()返回唯一的非空值,并在部署后重新加载表单编辑器。
每个文件都已被拒绝,即使干净的文件也是如此。 验证器无法关闭,因此这通常意味着它无法访问clamd。 重新检查步骤1(clamd是否正在运行并返回PONG?) 和步骤6(主机、端口、超时)。 在error.log中查找连接错误或ERROR响应。
扫描超时或INSTREAM size limit exceeded. 文件太大,超时或clamd的StreamMaxLength无法处理。 在步骤6中增加超时,在clamd.conf中提高StreamMaxLength,并在文件附件组件中设置最大文件大小,以便过大的文件提前停止。
EICAR提交显示一般错误,而不是内联字段消息(步骤10)。 提交到REST终结点提交操作应具有此属性;它不会更改文件是否实际被拒绝。 检查error.log验证器的拒绝消息以进行确认。
常见问题解答 faq
AEM Forms能否使用ClamAV扫描上载?
是的。您通过服务实施FileAttachmentValidator接口,该服务在提交时将每个上载的文件流式传输到ClamAV守护程序(clamd),如果ClamAV报告有威胁,则拒绝该文件。
是否需要在AEM服务器上安装ClamAV?
否。clamd作为单独的进程运行。您的验证器通过TCP与其连接。在本地运行它以进行开发,并在实际环境中作为合用位置或外部服务。
Clamd使用哪个端口?
默认情况下,TCP端口3310。示例验证器使用此端口,并允许您通过OSGi配置更改此端口。
如何测试病毒扫描的工作方式?
提交普通文件以确认接受,然后提交EICAR测试文件(一个无害的行业标准测试字符串)以确认检测到并阻止它。
为什么我的所有文件都被拒绝?
样本验证器无法关闭,因此clamd的连接问题导致每个文件都被拒绝。确认clamd正在运行且可访问,并检查主机、端口和超时设置。
我可以将ClamAV与AEM as a Cloud Service结合使用吗?
是,但无法在AEM主机上运行clamd。将其作为共处位置或外部服务运行,并将验证器指向该服务,最好是在同一区域,以便在您的环境中保留文件内容。
文件一附上,我能否在提交之前运行检查?
是的。本教程的验证器在提交时运行。要在用户附加文件后立即进行验证,请在提交之前,使用自适应Forms规则编辑器中的 调用服务 操作在文件字段的更改事件上调用扫描服务。请参阅规则编辑器中的调用服务增强功能。