昨天,我在使用资源类型属性注册的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请求是admin-user,则Servlet可以正常工作。所以脚本解析工作正常,这是一个权限问题。
在多个层检查权限:
权限检查 - 调度程序:调度程序可能会禁止某些路径的POST请求,或者需要某种身份验证,或者只是从请求中删除一些查询参数或其他有效负载。但是,如果错误消息来自Apache或发布者,则很容易识别。否则,您可以通过Dispatcher一次发送POST请求,然后直接发送给发布者。如果结果不同,那么您必须首先注意Dispatcher。
权限检查 - Apache Sling身份验证服务:这主要与作者相关,因为默认情况下Publisher非常开放。该服务简单地说,哪些路径可以作为匿名访问(意味着没有任何身份验证),以及用户转发到登录页面的路径。可以通过OSGi配置此服务,也可以直接在Servlet中指定sling.auth.requirements
属性。身份验证服务将读取此类属性,并将其视为自身的配置。如前所述,它主要与作者相关 - 因为默认情况下只有登录页面可以在没有身份验证的情况下访问。
权限检查 - 内容资源:如果通过SlingResourceType注册Servlet,则脚本解析过程需要对所请求资源的读取权限。在发布者中,/content/...
-tree通常对Anonymous可读,但不像/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 ...
。
你需要:
请按照以下说明操作:
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与低级API混合使用。可能会出现例外情况 - 但不适用于初学者。 (例如,PageManager-API建立在Slings Resource-API之上,它建立在Jackrabbit OAK的Node-API之上。难以知道哪些API存在)