java - sling servlet 上的发布请求不适用于发布实例
问题描述
昨天,我在使用资源类型属性注册的 AEM 6.3 中编写 sling post servlet 时遇到了问题。实际上我的代码适用于作者实例,但不适用于发布实例。下面的代码使用用户给定的数据在项目的内容路径上创建一个节点和属性。(以下代码中忽略import语句和分号,它是用groovy编写的)
我不确定,通过使用 SlingHttpServletRequest实例并获取会话来解析资源是否是一种好习惯?
而且,我能够找到 session.save() 或 resolver.commit 之间的任何区别。
有人可以帮忙吗?
@SlingServlet(
resourceTypes = ["app/project/components/formComp"],
extensions = ['json'],
methods = "POST")
@Properties([
@Property(name = "Code ABC", value = 'Project ABC'),
@Property(name = "Description ABC", value = 'servlet form')])
@CompileStatic
@Slf4j
class PostFormServlet extends SlingAllMethodsServlet {
ResourceResolver resolver
Session session
@Override
void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) {
String myNodePath = 'content/project/en/mynode'
String requestParam = 'param'
try {
resolver = request.getResourceResolver()
session = resolver.adaptTo(Session)
Node root = session.getRootNode()
Node myDestinationNode
if (rootNode.hasNode(myNodePath)) {
myDestinationNode = rootNode.getNode(myNodePath)
} else {
myDestinationNode = rootNode.addNode(myNodePath, NT_UNSTRUCTURED)
}
String paramValue = request.getParameter(requestParam)
if (myDestinationNode) {
Date date = new Date();
timeStamp = date.getTime() as String
Node dateTimeNode = myDestinationNode.addNode(timeStamp, NT_UNSTRUCTURED)
if (dateTimeNode) {
dateTimeNode.setProperty(requestParam, paramValue)
}
}
session.save()
} catch (Exception ex) {
//log error
}
response.contentType = 'application/json'
response.getWriter().write("Node Created")
}
}
解决方案
如果 POST 请求是作为管理员用户发出的,那么您的 Servlet 可以工作。所以脚本解析工作正常,这是权限问题。
权限检查在几个层次:
权限检查 - 调度程序: 调度程序可能不允许某些路径的 POST 请求,或者需要某种身份验证,或者只是从请求中删除一些查询参数或其他有效负载。但是很容易识别,错误消息是来自 Apache 还是来自 Publisher。否则,您可以通过 Dispatcher 发送 POST 请求一次,然后直接向 Publisher 发送一次。如果结果不同,那么您必须首先照顾 Dispatcher。
权限检查 - Apache Sling 身份验证服务:这主要与作者相关,因为默认情况下发布者非常开放。该服务简单地说,哪些路径可以匿名访问(意味着无需任何身份验证),以及哪些路径用户被转发到登录页面。该服务可以通过 OSGi 进行配置,或者sling.auth.requirements
直接在您的 Servlet 中指定一个属性。身份验证服务将读取此类属性,并将其视为自身的配置。如前所述,它主要与作者相关 - 因为默认情况下只有登录页面可以在没有身份验证的情况下访问。
权限检查 - 内容资源:如果您通过 SlingResourceType 注册 Servlet,则脚本解析过程需要对所请求资源的读取权限。在 Publisher 中,/content/...
-tree 通常对于匿名者来说是可读的,但不是/app/...
. 如果您在路径上注册 Servlet,您可以轻松避免这种情况。对于这样的 servlet,没有 Sling 权限检查(好坏,取决于你想要什么)。
Servlet 的权限
上述权限检查是相关的,即调用了您的 Servlet。但是如果被调用,Servlet 仍然只有调用用户的读写权限。这对于匿名用户来说非常非常少(阅读/内容/...,没有写权限)。
因此,您需要与服务用户打开一个新会话。
public class TestServlet extends SlingAllMethodsServlet {
@Reference
private ResourceResolverFactory resolverFactory;
@Override
protected void doPost(@Nonnull SlingHttpServletRequest request, @Nonnull SlingHttpServletResponse response) throws ServletException, IOException {
final Map<String, Object> authenticationInfo = Collections.singletonMap(ResourceResolverFactory.SUBSERVICE, "testservlet");
try (ResourceResolver resolver = resolverFactory.getServiceResourceResolver(authenticationInfo)) {
Resource rootRes = resolver.getResource("/content/....");
resolver.create(rootRes, "test", null);
resolver.commit();
} catch (Exception e) {
response.setContentType("text/plain");
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
e.printStackTrace(response.getWriter());
}
}
}
一开始,它会说类似org.apache.sling.api.resource.LoginException: Cannot derive user name for bundle ...
.
你需要:
- 创建一个系统用户(普通用户将无法使用!)
- 添加服务用户映射 (OSGi-config)
- 授予系统用户读/写权限
请遵循以下说明:
https://helpx.adobe.com/experience-manager/6-3/sites/administering/using/security-service-users.html
或者使用工具来创建服务用户并为他们授予权限。要么你已经使用了,要么我推荐https://github.com/Netcentric/accesscontroltool。映射仍然需要 OSGi 配置。
If the service user is too complicated for a first trial, you can still use the deprecated ResourceResolver resolver = resolverFactory.getAdministrativeResourceResolver(null)
. It is not secure, and therefore deprecated. You only have to whitelist your bundle via an OSGi config (Apache Sling Login Admin Whitelist - additional bundles)
Final question :
difference between session.save() or resolver.commit
The resolver is the Sling-wrapper around the Jackrabbit-Oak session. So resolver.commit() is calling session.save() automatically (but NOT the other way around).
It is strongly recommended to use the most high-level API you can - and NOT mixing high-level with low-level API's. Exceptions may occur - but not for beginners. (e.g. the PageManager-API is built on top of the Slings Resource-API, which is built on top of the Jackrabbit OAK's Node-API. The difficulty is to know, which API's exist)
推荐阅读
- javascript - checkall / un-checkall check boxes with js
- javascript - 如何更改 Yup/Formik 中的默认错误文本?
- ruby-on-rails - 如何使用 redirect_to 创建警报
- ruby-on-rails - 如何使用 Rails 连接到 PostgreSQL 容器
- typescript - 即使我用条件检查它是否存在,对象也可能未定义
- angular - Renderer.addClass() 上有多个类
- kotlin - 具有多个键和值的映射
- java - 声明正确的类型以适应泛型类型的函数调用
- c# - 在固定平局上画一个移动点
- reactjs - 如何在带有样式组件的伪元素上传递道具?