Unlock the Secrets of Filters in AEM: Boost Performance, Enhance Security and Implement Custom Logic
Filters in Adobe Experience Manager (AEM) are a powerful feature that allows developers to intercept and manipulate requests before they are handled by the AEM application. They can be used to perform tasks such as caching, compression, authentication, and more. Filters in AEM are implemented as a chain of OSGi services, which are executed in a specific order. Developers can create custom filters by implementing the
javax.servlet.Filterinterface and configuring them through the OSGi framework. In addition, AEM provides a set of built-in filters for common tasks, such as theCacheFilterfor caching responses, theGZipFilterfor compressing responses, and theSlingAuthenticatorfor handling authentication. Filters in AEM are powerful tools that can be used to improve the performance of an AEM application and enhance the user experience.
In AEM, there are several types of filters that can be used, including:
- Sling Filters: These filters are executed by the Sling Servlet and are used to modify the request and response, such as for authentication, caching, or logging. For example, a Sling filter can be used to add a header to the response or to check if the user is logged in before allowing them to access a specific resource. Sling filters are configured in the Sling Filter Manager, which allows you to apply them to specific paths or servlets.
Use case: A Sling filter can be used to cache the response of a certain path to improve the performance of the website.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = Filter.class, property = {
Constants.SERVICE_DESCRIPTION + "=Cache Filter",
"sling.filter.scope=request",
"sling.filter.pattern=/content/mypage"
})
public class CacheFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(CacheFilter.class);
private static final int CACHE_TIME = 3600; // one hour
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Cache-Control", "public, max-age=" + CACHE_TIME);
httpResponse.setDateHeader("Expires", System.currentTimeMillis() + CACHE_TIME * 1000);
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}Best Practices:
- Always make sure to properly close resources and release them after they are no longer needed.
- Avoid using heavy computation in filters as it would increase the response time.
- Always use the appropriate filter type for the use case.
Pros:
- Sling Filters are easy to implement and use.
- They can be used for various use cases such as logging, caching, and access control.
- They can be applied to specific paths or servlets.
Cons:
- They are executed for every request and can slow down the performance if not used efficiently.
2. URL Rewrite Filters: These filters are used to modify the URL of a request before it is processed by the Sling Servlet. For example, a URL Rewrite filter can be used to redirect a request from one URL to another or to change the case of the URL.
Use case: A URL rewrite filter can be used to redirect all requests to a non-www version of the website to the www version of the website.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = Filter.class, property = {
Constants.SERVICE_DESCRIPTION + "=WWW Redirect Filter",
"sling.filter.scope=request",
"sling.filter.pattern=/.*"
})
public class WWWRedirectFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(WWWRedirectFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String host = httpRequest.getServerName();
if (!host.startsWith("www.")) {
String redirectUrl = "https://www." + host + httpRequest.getRequestURI();
httpResponse.setStatus(301);
httpResponse.setHeader("Location", redirectUrl);
httpResponse.setHeader("Connection", "close");
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
}Best Practices:
- Use redirects only when it’s necessary and use them with caution, as it can negatively impact SEO.
- Use the appropriate HTTP status codes for redirects.
Pros:
- URL Rewrite Filters can be used to change the URL of a request before it is processed by the Sling Servlet.
- They can be used to redirect users to a specific URL.
Cons:
- They can negatively impact SEO if not used correctly.
3. Component Context Filters: These filters are executed before the component is rendered and are used to modify the context of the component. For example, a Component Context filter can be used to add data to the component’s context that is not available in the resource or to change the resource that the component is based on.
Use case: A Component Context filter can be used to add a custom resource to the component’s context, that is needed for the component to function.
import java.io.IOException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.wcm.api.components.ComponentContext;
import com.day.cq.wcm.api.components.ComponentFilter;
@Component(service = ComponentFilter.class, property = {
"sling.filter.scope=component"
})
public class CustomResourceFilter implements ComponentFilter {
private static final Logger log = LoggerFactory.getLogger(CustomResourceFilter.class);
@Override
public void filter(SlingHttpServletRequest request, SlingHttpServletResponse response, ComponentContext componentContext)
throws IOException {
Resource componentResource = componentContext.getResource();
Resource customResource = componentResource.getResourceResolver().getResource("/etc/custom-data/data");
componentContext.getRequest().setAttribute("customResource", customResource);
}
}Best Practices:
- Use the appropriate filter type for the use case.
- Use Component Context Filters only when it’s necessary, as they are executed for every component that is rendered.
- Be mindful of the data that is added to the component’s context, as it can negatively impact performance.
Pros:
- Component Context Filters can be used to add data to the component’s context that is not available in the resource.
- They can be used to change the resource that the component is based on.
Cons:
- They are executed for every component that is rendered and can slow down the performance if not used efficiently.
Please keep in mind that the above code examples are meant to provide a general idea of how filters can be implemented in AEM and may not work as is in your specific use case. It’s important to thoroughly test the filters before deploying them to a production environment.
4. Authentication Filters: These filters are used to handle authentication and authorization for a specific resource or set of resources. They can be used to protect specific resources from unauthorized access, to redirect users to a login page if they are not authenticated, or to perform other authentication-related tasks.
Use case: An Authentication filter can be used to protect a specific set of resources from unauthorized access.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = Filter.class, property = {
Constants.SERVICE_DESCRIPTION + "=Protected Resources Filter",
"sling.filter.scope=request",
"sling.filter.pattern=/content/protected-resources/.*"
})
public class ProtectedResourcesFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(ProtectedResourcesFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (!httpRequest.getRemoteUser().equals("admin")) {
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}Best Practices:
- Use the appropriate filter type for the use case.
- Use Authentication Filters only when it’s necessary, as they are executed for every request.
- Make sure to properly close resources and release them after they are no longer needed.
Pros:
- Authentication Filters can be used to handle authentication and authorization for a specific resource or set of resources.
- They can be used to protect specific resources from unauthorized access.
Cons:
- They are executed for every request and can slow down performance if not used efficiently.
- Incorrectly implemented filters can result in security vulnerabilities.
- Depending on the complexity of the authentication and authorization requirements, implementing a custom filter may not be the best solution and it might be necessary to use an external authentication system or a more comprehensive access control solution.
It’s important to evaluate the specific use case and the requirements of your application before deciding to use an authentication filter. It’s also important to test the filter thoroughly and make sure it’s properly configured and implemented to avoid security vulnerabilities.
5. Client-side Filters: These filters are used to modify the HTML, CSS, or JavaScript of a page before it is sent to the browser. They can be used to add analytics tracking code, to minify HTML, CSS, or JavaScript, or to perform other client-side tasks.
Use case: A client-side filter can be used to minify the HTML, CSS, and JavaScript of a page before it is sent to the browser.
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = Filter.class, property = {
Constants.SERVICE_DESCRIPTION + "=HTML Minify Filter",
"sling.filter.scope=component",
"sling.filter.pattern=/content/.*\\.html"
})
public class HTMLMinifyFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(HTMLMinifyFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
MinifyResponseWrapper minifyResponseWrapper = new MinifyResponseWrapper(httpResponse);
chain.doFilter(request, minifyResponseWrapper);
String minifiedHtml = minifyHtml(minifyResponseWrapper.toString());
httpResponse.getWriter().write(minifiedHtml);
}
private String minifyHtml(String html) {
// Minify the HTML here
return minifiedHtml;
}
@Override
public void destroy() {
}
}Best Practices:
- Use client-side filters only when necessary, as they can increase the load time of a page.
- Use a minification library to minify HTML, CSS and JavaScript.
- Be mindful of the order in which the filters are executed, as the order can affect the final output.
Pros:
- Client-side filters can be used to add analytics tracking code, to minify HTML, CSS and JavaScript, or to perform other client-side tasks.
- They can improve the load time of a page by reducing the size of the HTML, CSS and JavaScript.
Cons:
- They can increase the load time of a page if not implemented efficiently.
- It can be difficult to debug issues that arise from client-side filters.
- It’s important to ensure that the filters are applied to the appropriate resources and in the appropriate order to avoid unexpected behavior.
Please keep in mind that the above code examples are meant to provide a general idea of how filters can be implemented in AEM and may not work as is in your specific use case. It’s important to thoroughly test the filters before deploying them to a production environment.
6. Logging Filters: These filters are used to log information about the request and response. They can be used to log information such as the URL, the IP address of the client, the user agent, and other request-related information.
Use case: A logging filter can be used to log the URL, IP address, and user agent of each request:
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component(service = Filter.class, property = {
Constants.SERVICE_DESCRIPTION + "=Request Logging Filter",
"sling.filter.scope=request",
"sling.filter.pattern=/.*"
})
public class RequestLoggingFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
log.info("URL: {}", httpRequest.getRequestURL());
log.info("IP: {}", httpRequest.getRemoteAddr());
log.info("User Agent: {}", httpRequest.getHeader("User-Agent"));
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}Best Practices:
- Use logging filters only when necessary, as they can have a performance impact.
- Use a logging framework such as Log4j or SLF4J to log the information.
- Be mindful of the sensitive data that is being logged, and make sure to mask or encrypt it if necessary.
Pros:
- Logging filters can be used to log information about the request and response.
- They can be used for troubleshooting and debugging.
Cons:
- They can have a performance impact if not used efficiently.
- They can log sensitive data, so it’s important to make sure that the data is masked or encrypted if necessary.
- It’s important to ensure that the filters are applied to the appropriate resources.
- They can generate a large amount of log data, which can impact storage and maintenance.
- If not configured properly, they can expose sensitive information in the logs.
It’s important to evaluate the specific use case and the requirements of your application before deciding to use a logging filter. It’s also important to test the filter thoroughly and make sure it’s properly configured and implemented to avoid security vulnerabilities and performance issues.
In addition to the above filter types and examples, there are many other types of filters that can be implemented in AEM, such as compression filters, error handling filters, and more. It’s important to choose the right filter for the specific use case and to implement them correctly to ensure optimal performance and security.
In conclusion, filters are a powerful tool in AEM that can be used to perform a wide range of tasks. They can be used to improve the performance of a site, to add security, to implement custom logic, and more. It’s important to choose the right filter for the specific use case and to implement them correctly to ensure optimal performance and security.
Would you like to support me? You can support my work if you enjoy reading my stories. Sign up for my newsletter and get my stories straight to your inbox.
To get access to my unlimited stories, you can also consider signing up to become a Medium member for just $ 5. If you sign up using my link, I will receive a small commission (at no extra cost to you).




