User Provisioning Filter
In this lesson, we'll implement a filter that creates new users in our database when they first log in, ensuring every authenticated user has a corresponding User in the database.
Understanding User Provisioning
A user provisioning filter intercepts incoming requests after authentication to check if a user exists in our database and creates them if they don't.
This filter is valuable because it automatically creates user records in our database when users first authenticate through Keycloak, without requiring additional API endpoints or manual intervention.
Implementing the User Repository
First, we need a repository to interact with our user database:
@Repository
public interface UserRepository extends JpaRepository<User, UUID> {
}By extending JpaRepository, we get built-in methods for:
- Creating users
- Checking if users exist
- Finding users by ID
- And many other common database operations
Creating the User Provisioning Filter
The filter needs to:
- Extract user information from the JWT token
- Check if the user exists in our database
- Create the user if they don't exist
Here's the implementation:
@Component
@RequiredArgsConstructor
public class UserProvisioningFilter extends OncePerRequestFilter {
private final UserRepository userRepository;
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Get the authentication object from the security context
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null
&& authentication.isAuthenticated()
&& authentication.getPrincipal() instanceof Jwt jwt) {
// Extract the user ID from the JWT subject
UUID keycloakId = UUID.fromString(jwt.getSubject());
if (!userRepository.existsById(keycloakId)) {
User user = new User();
user.setId(keycloakId);
user.setName(jwt.getClaimAsString("preferred_username"));
user.setEmail(jwt.getClaimAsString("email"));
userRepository.save(user);
}
}
filterChain.doFilter(request, response);
}
}The filter extends OncePerRequestFilter to ensure it only runs once per request.
We use @RequiredArgsConstructor to inject our UserRepository through constructor injection.
The filter checks if we have an authenticated user with a JWT token, then extracts the user ID and creates a new user record if one doesn't exist.
Summary
- Created the
UserRepositoryinterface - Implemented the
UserProvisioningFilter