java 43 lines · 8 steps

How a tenant-resolution filter works in Spring

A servlet filter reads a tenant header, validates it against the database, and binds it to thread-local context for the request.

Explained by highlit
1@Component
2@Order(Ordered.HIGHEST_PRECEDENCE)
3public class TenantResolutionFilter extends OncePerRequestFilter {
4 
5 private static final String TENANT_HEADER = "X-Tenant-ID";
6 
7 private final TenantRepository tenantRepository;
8 
9 public TenantResolutionFilter(TenantRepository tenantRepository) {
10 this.tenantRepository = tenantRepository;
11 }
12 
13 @Override
14 protected void doFilterInternal(HttpServletRequest request,
15 HttpServletResponse response,
16 FilterChain filterChain) throws ServletException, IOException {
17 String tenantId = request.getHeader(TENANT_HEADER);
18 
19 if (!StringUtils.hasText(tenantId)) {
20 response.sendError(HttpStatus.BAD_REQUEST.value(), "Missing " + TENANT_HEADER + " header");
21 return;
22 }
23 
24 Tenant tenant = tenantRepository.findByExternalId(tenantId).orElse(null);
25 if (tenant == null || !tenant.isActive()) {
26 response.sendError(HttpStatus.FORBIDDEN.value(), "Unknown or inactive tenant");
27 return;
28 }
29 
30 try {
31 TenantContext.setCurrentTenant(tenant);
32 response.setHeader(TENANT_HEADER, tenant.getExternalId());
33 filterChain.doFilter(request, response);
34 } finally {
35 TenantContext.clear();
36 }
37 }
38 
39 @Override
40 protected boolean shouldNotFilter(HttpServletRequest request) {
41 return request.getRequestURI().startsWith("/actuator");
42 }
43}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Running a filter at highest precedence lets you establish request-scoped context before any other component executes.
  2. 2Thread-local context must always be cleared in a finally block to avoid leaking state across pooled request threads.
  3. 3Validating identity early and failing with the right HTTP status keeps invalid requests out of your business logic.

Related explainers

Share this explainer

Here's the card — post it anywhere.

How a tenant-resolution filter works in Spring — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code