A custom permission evaluator lets you control who can do what in your app by checking permissions in your own way.
Custom permission evaluator in Spring Boot
Start learning this pattern below
Jump into concepts and practice - no test required
public class MyPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) { // Your custom logic here return false; } @Override public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) { // Your custom logic here return false; } }
Implement the PermissionEvaluator interface to create your own permission checks.
Override both hasPermission methods to handle different permission scenarios.
public class MyPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) { if (auth == null || targetDomainObject == null || !(permission instanceof String)) { return false; } String perm = (String) permission; // Example: allow if user has 'ADMIN' role return auth.getAuthorities().stream() .anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN")); } @Override public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) { return false; } }
public class MyPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) { if (targetDomainObject instanceof Document) { Document doc = (Document) targetDomainObject; String perm = (String) permission; // Allow if user owns the document return doc.getOwner().equals(auth.getName()); } return false; } @Override public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) { return false; } }
This custom permission evaluator allows users with the 'ROLE_USER' role to have 'read' permission on any object.
package com.example.security; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; import java.io.Serializable; public class CustomPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication auth, Object targetDomainObject, Object permission) { if (auth == null || targetDomainObject == null || !(permission instanceof String)) { return false; } String perm = (String) permission; // Simple example: allow if user has 'ROLE_USER' and permission is 'read' boolean hasRoleUser = auth.getAuthorities().stream() .anyMatch(a -> a.getAuthority().equals("ROLE_USER")); if (hasRoleUser && "read".equalsIgnoreCase(perm)) { return true; } return false; } @Override public boolean hasPermission(Authentication auth, Serializable targetId, String targetType, Object permission) { // Not implemented for this example return false; } }
Register your custom PermissionEvaluator as a bean in your Spring Security configuration.
Use @PreAuthorize or @PostAuthorize annotations with expressions like hasPermission() to apply your evaluator.
Test your permission logic carefully to avoid accidental access.
Custom permission evaluators let you write your own rules for who can do what.
Implement the PermissionEvaluator interface and override its methods.
Use your evaluator in security annotations to protect your app.
Practice
Custom PermissionEvaluator in Spring Boot security?Solution
Step 1: Understand the role of PermissionEvaluator
The PermissionEvaluator interface allows defining custom logic to check if a user has permission to perform an action.Step 2: Identify the purpose of custom implementation
Implementing a custom PermissionEvaluator lets you write your own rules that can be reused across your application for security checks.Final Answer:
To define custom rules for checking user permissions in a reusable way -> Option CQuick Check:
Custom PermissionEvaluator = Custom reusable permission rules [OK]
- Thinking it replaces Spring Security entirely
- Confusing it with session management
- Assuming it manages database connections
PermissionEvaluator to check permissions based on a target domain object?Solution
Step 1: Recall PermissionEvaluator interface methods
PermissionEvaluator has two methods: one with targetDomainObject and one with targetId and targetType.Step 2: Identify the method for domain object permission check
The methodhasPermission(Authentication authentication, Object targetDomainObject, Object permission)is used to check permissions on a domain object.Final Answer:
hasPermission(Authentication authentication, Object targetDomainObject, Object permission) -> Option BQuick Check:
Domain object permission method = hasPermission with targetDomainObject [OK]
- Choosing methods not in PermissionEvaluator interface
- Confusing method parameters
- Using method names that don't exist
public boolean hasPermission(Authentication auth, Object target, Object perm) {
if (auth == null || target == null || !(perm instanceof String)) {
return false;
}
String permission = (String) perm;
User user = (User) auth.getPrincipal();
return user.getRoles().contains(permission);
}What will be the result if
auth is null?Solution
Step 1: Analyze the null check at method start
The method checks ifauthis null and returns false immediately if so.Step 2: Understand the flow when auth is null
Sinceauth == nulltriggers return false, no further code runs and no exception occurs.Final Answer:
Returns false immediately -> Option AQuick Check:
Null auth returns false immediately [OK]
- Assuming NullPointerException will be thrown
- Thinking it returns true by default
- Ignoring the null check logic
public boolean hasPermission(Authentication auth, Object target, Object perm) {
String permission = (String) perm;
User user = (User) auth.getPrincipal();
return user.getRoles().contains(permission);
}What is the main problem with this code?
Solution
Step 1: Check for missing null validations
The method does not check ifauth,perm, orauth.getPrincipal()are null before casting or calling methods.Step 2: Understand consequences of missing null checks
If any are null, the code will throw NullPointerException at runtime.Final Answer:
It lacks null checks and may throw NullPointerException -> Option DQuick Check:
Missing null checks cause runtime exceptions [OK]
- Ignoring null safety
- Thinking casting is always safe
- Assuming roles check is invalid
Which code snippet correctly implements this logic inside
hasPermission?Solution
Step 1: Check for null authentication and target
Security checks should return false if authentication or target is null to avoid errors.Step 2: Verify user role and document status conditions
The user must have "EDITOR" role and the document status must be exactly "DRAFT" for permission to be granted.Step 3: Confirm correct logical operator usage
Both conditions must be true, so use logical AND (&&), not OR (||).Final Answer:
if (auth == null || target == null) return false; User user = (User) auth.getPrincipal(); Document doc = (Document) target; return user.getRoles().contains("EDITOR") && "DRAFT".equals(doc.getStatus()); -> Option AQuick Check:
Check nulls + role AND status = correct logic [OK]
- Using || instead of && for both conditions
- Not checking for null auth or target
- Comparing strings with == instead of equals()
