在吊索servlet上的发布请求不适用于发布实例

时间:2018-09-16 20:54:54

标签: java servlets aem sling

昨天,我在用资源类型属性注册的AEM 6.3中编写sling post servlet时遇到问题。实际上,我的代码适用于作者实例,但不适用于发布实例。下面的代码使用用户给定的数据在项目的内容路径上创建节点和属性。 (忽略以下代码中的导入语句和分号,它是用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")
    }
}

1 个答案:

答案 0 :(得分:3)

如果POST请求是以admin-user身份进行的,则您的Servlet可以工作。因此,脚本解析效果很好,这是一个权限问题。

在几层检查权限:

权限检查-调度程序: 分派器可能不允许某些路径的POST请求,或者需要某种身份验证,或者只是从请求中删除一些查询参数或其他有效负载。但是,如果错误消息是来自Apache还是来自发布服务器,则很容易识别。否则,您可以通过分派器发送一次POST请求,然后直接发送到发布者一次。如果结果有所不同,则必须首先照顾Dispatcher。

权限检查-Apache Sling身份验证服务:这主要与作者有关​​,因为默认情况下发布者非常开放。该服务简单地说,可以匿名访问哪些路径(意味着无需任何身份验证),以及将用户转发到登录页面的路径。可以通过OSGi或通过直接在Servlet中指定sling.auth.requirements属性来配置此服务。身份验证服务将读取此类属性,并将其视为自身的配置。如前所述,它主要与作者有关​​-默认情况下,只有登录页面无需身份验证即可访问。

权限检查-内容资源:如果您通过SlingResourceType注册Servlet,则脚本解析过程需要对所请求资源的读取权限。在发布者处,/content/...树通常对于匿名者是可读的,但不像/app/...这样。如果在路径上注册Servlet,则可以轻松避免这种情况。对于此类servlet,没有Sling权限检查(好坏取决于所需要的内容)。


Servlet的权限

上面的权限检查是相关的,即您的Servlet被调用。但是,如果被调用,则Servlet仍然仅具有调用用户的读取和写入权限。

读/ content / ...,没有写权限

因此,您需要与服务用户打开一个新会话。

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 ...

您需要:

  1. 创建系统用户(普通用户将无法使用!)
  2. 添加服务用户映射(OSGi-config)
  3. 授予系统用户读/写权限

请遵循以下说明:

https://helpx.adobe.com/experience-manager/6-3/sites/administering/using/security-service-users.html

或使用工具创建服务用户并为其授予权限。您已经使用过一个,或者我建议使用https://github.com/Netcentric/accesscontroltool。映射仍然需要OSGi配置。


如果服务用户对于第一次试用而言过于复杂,则仍然可以使用不推荐使用的ResourceResolver resolver = resolverFactory.getAdministrativeResourceResolver(null)。它不安全,因此已弃用。您只需要通过OSGi配置将捆绑软件列入白名单(Apache Sling登录管理员白名单-其他捆绑软件)


最后一个问题:

  

session.save()或resolver.commit之间的差异

解析器是围绕Jackrabbit-Oak会话的Sling-wrapper。因此resolver.commit()是自动调用session.save()的(但不是这样)。

强烈建议使用您可以使用的最高级别的API-请勿将高级和低级API混合使用。可能会发生例外-但对于初学者而言不会。 (例如,PageManager-API是建立在Slings Resource-API之上的,而Slings Resource-API是建立在Jackrabbit OAK的Node-API之上的。困难是要知道哪个API存在)