google-site-verification: google61fe8ba583a51912.html
Casbin for Authorization in Java: Powerful Access Control Framework

Casbin is a powerful and efficient open-source access control library that supports various authorization models like ACL, RBAC, ABAC. It provides a unified way to handle authorization across different applications and frameworks.

Casbin Authorization Models

  1. ACL (Access Control List) - Basic user-resource permissions
  2. RBAC (Role-Based Access Control) - Permissions through roles
  3. ABAC (Attribute-Based Access Control) - Context-aware permissions
  4. RESTful Model - HTTP method and path based control

Dependencies and Setup

Maven Configuration:

<dependencies> <!-- Casbin Core --> <dependency> <groupId>org.casbin</groupId> <artifactId>jcasbin</artifactId> <version>1.39.0</version> </dependency> <!-- Spring Boot Integration --> <dependency> <groupId>org.casbin</groupId> <artifactId>jcasbin-spring-boot-starter</artifactId> <version>3.1.0</version> </dependency> <!-- Database Adapters --> <dependency> <groupId>org.casbin</groupId> <artifactId>jdbc-adapter</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.casbin</groupId> <artifactId>redis-adapter</artifactId> <version>3.1.0</version> </dependency> <!-- Spring Security Integration --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- Database (if using JDBC adapter) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>

Core Configuration

CasbinProperties.java:

@Configuration @ConfigurationProperties(prefix = "casbin") @Data public class CasbinProperties { private ModelConfig model = new ModelConfig(); private AdapterConfig adapter = new AdapterConfig(); private WatcherConfig watcher = new WatcherConfig(); @Data public static class ModelConfig { private String path = "classpath:casbin/model.conf"; private boolean enabled = true; } @Data public static class AdapterConfig { private AdapterType type = AdapterType.FILE; private String filePath = "classpath:casbin/policy.csv"; private JdbcConfig jdbc = new JdbcConfig(); private RedisConfig redis = new RedisConfig(); } @Data public static class JdbcConfig { private String url; private String username; private String password; private String driverClassName; private String tableName = "casbin_rule"; } @Data public static class RedisConfig { private String host = "localhost"; private int port = 6379; private String password; private int database = 0; } @Data public static class WatcherConfig { private boolean enabled = false; private WatcherType type = WatcherType.REDIS; } public enum AdapterType { FILE, JDBC, REDIS, MONGO } public enum WatcherType { REDIS, ZOOKEEPER } }

Casbin Model Configuration

model.conf:

[request_definition] r = sub, obj, act

[policy_definition]

p = sub, obj, act

[role_definition]

g = _, _

[policy_effect]

e = some(where (p.eft == allow))

[matchers]

m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")

Advanced RBAC with Domains:

[request_definition] r = sub, dom, obj, act

[policy_definition]

p = sub, dom, obj, act

[role_definition]

g = _, _, _

[policy_effect]

e = some(where (p.eft == allow))

[matchers]

m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)

ABAC Model:

[request_definition] r = sub, obj, act

[policy_definition]

p = sub_rule, obj_rule, act_rule

[policy_effect]

e = some(where (p.eft == allow))

[matchers]

m = eval(p.sub_rule) && eval(p.obj_rule) && eval(p.act_rule)

[role_definition]

g = _, _

Casbin Service Configuration

CasbinConfig.java:

@Configuration @Slf4j public class CasbinConfig { private final CasbinProperties properties; private final DataSource dataSource; // Optional, for JDBC adapter public CasbinConfig(CasbinProperties properties, @Autowired(required = false) DataSource dataSource) { this.properties = properties; this.dataSource = dataSource; } @Bean @ConditionalOnMissingBean public Enforcer enforcer() { try { // Create model Model model = createModel(); // Create adapter Adapter adapter = createAdapter(); // Create enforcer Enforcer enforcer = new Enforcer(model, adapter); // Enable auto-save enforcer.enableAutoSave(true); // Enable auto-build role links enforcer.enableAutoBuildRoleLinks(true); // Load policy enforcer.loadPolicy(); // Add watcher if enabled if (properties.getWatcher().isEnabled()) { addWatcher(enforcer); } log.info("Casbin enforcer initialized successfully"); return enforcer; } catch (Exception e) { throw new CasbinConfigurationException("Failed to initialize Casbin enforcer", e); } } private Model createModel() { String modelPath = properties.getModel().getPath(); if (modelPath.startsWith("classpath:")) { modelPath = modelPath.substring("classpath:".length()); return new Model("src/main/resources/" + modelPath); } else { return new Model(modelPath); } } private Adapter createAdapter() { switch (properties.getAdapter().getType()) { case FILE: return createFileAdapter(); case JDBC: return createJdbcAdapter(); case REDIS: return createRedisAdapter(); default: throw new UnsupportedAdapterException( "Unsupported adapter type: " + properties.getAdapter().getType()); } } private Adapter createFileAdapter() { String filePath = properties.getAdapter().getFilePath(); if (filePath.startsWith("classpath:")) { filePath = filePath.substring("classpath:".length()); try { return new FileAdapter("src/main/resources/" + filePath); } catch (Exception e) { log.warn("Failed to load policy file, using in-memory adapter"); return new DefaultAdapter(); } } else { return new FileAdapter(filePath); } } private Adapter createJdbcAdapter() { if (dataSource == null) { throw new CasbinConfigurationException("DataSource required for JDBC adapter"); } JdbcAdapterConfig config = new JdbcAdapterConfig(); config.setDataSource(dataSource); config.setTableName(properties.getAdapter().getJdbc().getTableName()); return new JdbcAdapter(config); } private Adapter createRedisAdapter() { CasbinProperties.RedisConfig redisConfig = properties.getAdapter().getRedis(); RedisAdapterConfig config = new RedisAdapterConfig(); config.setHost(redisConfig.getHost()); config.setPort(redisConfig.getPort()); config.setPassword(redisConfig.getPassword()); config.setDatabase(redisConfig.getDatabase()); return new RedisAdapter(config); } private void addWatcher(Enforcer enforcer) { // Implement watcher for distributed policy updates // This would typically use Redis pub/sub or similar log.info("Watcher enabled for Casbin enforcer"); } }

Core Authorization Service

CasbinAuthService.java:

@Service @Slf4j public class CasbinAuthService { private final Enforcer enforcer; public CasbinAuthService(Enforcer enforcer) { this.enforcer = enforcer; } // Basic permission check public boolean checkPermission(String subject, String object, String action) { try { return enforcer.enforce(subject, object, action); } catch (Exception e) { log.error("Permission check failed for {}-{}-{}", subject, object, action, e); return false; } } // Permission check with domain (multi-tenant) public boolean checkPermission(String subject, String domain, String object, String action) { try { return enforcer.enforce(subject, domain, object, action); } catch (Exception e) { log.error("Permission check failed for {}-{}-{}-{}", subject, domain, object, action, e); return false; } } // Get all roles for a user public List<String> getRolesForUser(String username) { try { return enforcer.getRolesForUser(username); } catch (Exception e) { log.error("Failed to get roles for user: {}", username, e); return Collections.emptyList(); } } // Get all roles for user in domain public List<String> getRolesForUser(String username, String domain) { try { return enforcer.getRolesForUser(username, domain); } catch (Exception e) { log.error("Failed to get roles for user {} in domain {}", username, domain, e); return Collections.emptyList(); } } // Get all users for a role public List<String> getUsersForRole(String role) { try { return enforcer.getUsersForRole(role); } catch (Exception e) { log.error("Failed to get users for role: {}", role, e); return Collections.emptyList(); } } // Check if user has role public boolean hasRole(String username, String role) { try { return enforcer.hasRoleForUser(username, role); } catch (Exception e) { log.error("Failed to check role {} for user {}", role, username, e); return false; } } // Add role to user public boolean addRoleForUser(String username, String role) { try { boolean result = enforcer.addRoleForUser(username, role); if (result) { log.info("Added role {} to user {}", role, username); } return result; } catch (Exception e) { log.error("Failed to add role {} to user {}", role, username, e); return false; } } // Add role to user in domain public boolean addRoleForUser(String username, String role, String domain) { try { boolean result = enforcer.addRoleForUser(username, role, domain); if (result) { log.info("Added role {} to user {} in domain {}", role, username, domain); } return result; } catch (Exception e) { log.error("Failed to add role {} to user {} in domain {}", role, username, domain, e); return false; } } // Delete role for user public boolean deleteRoleForUser(String username, String role) { try { boolean result = enforcer.deleteRoleForUser(username, role); if (result) { log.info("Deleted role {} from user {}", role, username); } return result; } catch (Exception e) { log.error("Failed to delete role {} from user {}", role, username, e); return false; } } // Add permission public boolean addPermission(String subject, String object, String action) { try { boolean result = enforcer.addPolicy(subject, object, action); if (result) { log.info("Added permission {}-{}-{}", subject, object, action); } return result; } catch (Exception e) { log.error("Failed to add permission {}-{}-{}", subject, object, action, e); return false; } } // Delete permission public boolean deletePermission(String subject, String object, String action) { try { boolean result = enforcer.removePolicy(subject, object, action); if (result) { log.info("Deleted permission {}-{}-{}", subject, object, action); } return result; } catch (Exception e) { log.error("Failed to delete permission {}-{}-{}", subject, object, action, e); return false; } } // Get all permissions for user public List<List<String>> getPermissionsForUser(String username) { try { return enforcer.getPermissionsForUser(username); } catch (Exception e) { log.error("Failed to get permissions for user: {}", username, e); return Collections.emptyList(); } } // Get all permissions public List<List<String>> getAllPermissions() { try { return enforcer.getPolicy(); } catch (Exception e) { log.error("Failed to get all permissions", e); return Collections.emptyList(); } } // Batch add permissions public boolean addPermissions(List<Permission> permissions) { try { List<List<String>> policies = permissions.stream() .map(p -> Arrays.asList(p.getSubject(), p.getObject(), p.getAction())) .collect(Collectors.toList()); boolean result = enforcer.addPolicies(policies); if (result) { log.info("Added {} permissions in batch", permissions.size()); } return result; } catch (Exception e) { log.error("Failed to add batch permissions", e); return false; } } // Check with ABAC attributes public boolean checkWithAttributes(String subject, Map<String, Object> subjectAttrs, String object, Map<String, Object> objectAttrs, String action, Map<String, Object> actionAttrs) { try { // For ABAC, you would use a custom function in the matcher // This is a simplified example ABACRequest request = new ABACRequest(subject, subjectAttrs, object, objectAttrs, action, actionAttrs); return evaluateAbacRequest(request); } catch (Exception e) { log.error("ABAC permission check failed", e); return false; } } private boolean evaluateAbacRequest(ABACRequest request) { // Implement ABAC evaluation logic // This would typically use the eval() function in Casbin matchers return false; } @Data @AllArgsConstructor public static class Permission { private String subject; private String object; private String action; } @Data @AllArgsConstructor public static class ABACRequest { private String subject; private Map<String, Object> subjectAttributes; private String object; private Map<String, Object> objectAttributes; private String action; private Map<String, Object> actionAttributes; } }

Spring Security Integration

CasbinSecurityConfig.java:

@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true) @Slf4j public class CasbinSecurityConfig { private final CasbinAuthService casbinAuthService; public CasbinSecurityConfig(CasbinAuthService casbinAuthService) { this.casbinAuthService = casbinAuthService; } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authz -> authz .requestMatchers("/public/**").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) .addFilterBefore(casbinAuthorizationFilter(), BasicAuthenticationFilter.class) .formLogin(form -> form .loginPage("/login") .permitAll() ) .logout(logout -> logout .logoutSuccessUrl("/login?logout") .permitAll() ) .exceptionHandling(exceptions -> exceptions .accessDeniedHandler(casbinAccessDeniedHandler()) ); return http.build(); } @Bean public CasbinAuthorizationFilter casbinAuthorizationFilter() { return new CasbinAuthorizationFilter(casbinAuthService); } @Bean public AccessDeniedHandler casbinAccessDeniedHandler() { return (request, response, accessDeniedException) -> { response.setStatus(HttpStatus.FORBIDDEN.value()); response.setContentType("application/json"); Map<String, Object> error = new HashMap<>(); error.put("timestamp", Instant.now()); error.put("status", HttpStatus.FORBIDDEN.value()); error.put("error", "Forbidden"); error.put("message", "Access denied"); error.put("path", request.getRequestURI()); ObjectMapper mapper = new ObjectMapper(); response.getWriter().write(mapper.writeValueAsString(error)); }; } }

CasbinAuthorizationFilter.java:

@Component @Slf4j public class CasbinAuthorizationFilter extends OncePerRequestFilter { private final CasbinAuthService casbinAuthService; public CasbinAuthorizationFilter(CasbinAuthService casbinAuthService) { this.casbinAuthService = casbinAuthService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null || !authentication.isAuthenticated()) { filterChain.doFilter(request, response); return; } String username = authentication.getName(); String path = request.getRequestURI(); String method = request.getMethod(); // Check permission using Casbin boolean hasPermission = casbinAuthService.checkPermission(username, path, method); if (hasPermission) { filterChain.doFilter(request, response); } else { log.warn("Access denied for user {} to {} {}", username, method, path); response.setStatus(HttpStatus.FORBIDDEN.value()); Map<String, Object> error = Map.of( "error", "Forbidden", "message", "Insufficient permissions", "path", path, "timestamp", Instant.now() ); response.setContentType("application/json"); ObjectMapper mapper = new ObjectMapper(); response.getWriter().write(mapper.writeValueAsString(error)); } } @Override protected boolean shouldNotFilter(HttpServletRequest request) { String path = request.getRequestURI(); return path.startsWith("/public/") || path.equals("/login") || path.equals("/logout"); } }

Method Security with Annotations

CasbinMethodSecurityService.java:

@Service @Slf4j public class CasbinMethodSecurityService { private final CasbinAuthService casbinAuthService; public CasbinMethodSecurityService(CasbinAuthService casbinAuthService) { this.casbinAuthService = casbinAuthService; } @PreAuthorize("@casbinMethodSecurityService.hasPermission('read', #resource)") public Resource readResource(String resource) { log.info("Reading resource: {}", resource); return new Resource(resource, "content"); } @PreAuthorize("@casbinMethodSecurityService.hasPermission('write', #resource)") public void updateResource(String resource, String content) { log.info("Updating resource: {}", resource); } @PreAuthorize("@casbinMethodSecurityService.hasRole('ADMIN')") public void adminOperation() { log.info("Performing admin operation"); } @PreAuthorize("@casbinMethodSecurityService.hasPermission(#domain, 'read', 'data')") public List<Data> getDomainData(String domain) { log.info("Getting data for domain: {}", domain); return Collections.emptyList(); } // Permission check method used in @PreAuthorize public boolean hasPermission(String action, String resource) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { return false; } String username = authentication.getName(); return casbinAuthService.checkPermission(username, resource, action); } // Domain-based permission check public boolean hasPermission(String domain, String action, String resource) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { return false; } String username = authentication.getName(); return casbinAuthService.checkPermission(username, domain, resource, action); } // Role check method public boolean hasRole(String role) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { return false; } String username = authentication.getName(); return casbinAuthService.hasRole(username, role); } @Data @AllArgsConstructor public static class Resource { private String name; private String content; } @Data public static class Data { private String id; private String value; } }

REST API for Policy Management

CasbinPolicyController.java:

@RestController @RequestMapping("/api/admin/casbin") @PreAuthorize("hasRole('ADMIN')") @Slf4j public class CasbinPolicyController { private final CasbinAuthService casbinAuthService; private final Enforcer enforcer; public CasbinPolicyController(CasbinAuthService casbinAuthService, Enforcer enforcer) { this.casbinAuthService = casbinAuthService; this.enforcer = enforcer; } @GetMapping("/policies") public ResponseEntity<List<PolicyResponse>> getAllPolicies() { List<List<String>> policies = casbinAuthService.getAllPermissions(); List<PolicyResponse> response = policies.stream() .map(policy -> new PolicyResponse(policy.get(0), policy.get(1), policy.get(2))) .collect(Collectors.toList()); return ResponseEntity.ok(response); } @PostMapping("/policies") public ResponseEntity<PolicyResponse> addPolicy(@RequestBody PolicyRequest request) { boolean success = casbinAuthService.addPermission( request.getSubject(), request.getObject(), request.getAction()); if (success) { PolicyResponse response = new PolicyResponse( request.getSubject(), request.getObject(), request.getAction()); return ResponseEntity.ok(response); } else { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } @DeleteMapping("/policies") public ResponseEntity<Void> deletePolicy(@RequestBody PolicyRequest request) { boolean success = casbinAuthService.deletePermission( request.getSubject(), request.getObject(), request.getAction()); return success ? ResponseEntity.noContent().build() : ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } @GetMapping("/users/{username}/roles") public ResponseEntity<List<String>> getUserRoles(@PathVariable String username) { List<String> roles = casbinAuthService.getRolesForUser(username); return ResponseEntity.ok(roles); } @PostMapping("/users/{username}/roles") public ResponseEntity<Void> addUserRole(@PathVariable String username, @RequestBody RoleRequest request) { boolean success = casbinAuthService.addRoleForUser(username, request.getRole()); return success ? ResponseEntity.ok().build() : ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } @DeleteMapping("/users/{username}/roles/{role}") public ResponseEntity<Void> deleteUserRole(@PathVariable String username, @PathVariable String role) { boolean success = casbinAuthService.deleteRoleForUser(username, role); return success ? ResponseEntity.noContent().build() : ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } @GetMapping("/users/{username}/permissions") public ResponseEntity<List<PolicyResponse>> getUserPermissions(@PathVariable String username) { List<List<String>> permissions = casbinAuthService.getPermissionsForUser(username); List<PolicyResponse> response = permissions.stream() .map(permission -> new PolicyResponse( permission.get(0), permission.get(1), permission.get(2))) .collect(Collectors.toList()); return ResponseEntity.ok(response); } @PostMapping("/batch/policies") public ResponseEntity<Void> addPoliciesBatch(@RequestBody List<PolicyRequest> requests) { List<CasbinAuthService.Permission> permissions = requests.stream() .map(req -> new CasbinAuthService.Permission(req.getSubject(), req.getObject(), req.getAction())) .collect(Collectors.toList()); boolean success = casbinAuthService.addPermissions(permissions); return success ? ResponseEntity.ok().build() : ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } @PostMapping("/reload") public ResponseEntity<Void> reloadPolicy() { try { enforcer.loadPolicy(); log.info("Casbin policy reloaded successfully"); return ResponseEntity.ok().build(); } catch (Exception e) { log.error("Failed to reload Casbin policy", e); return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build(); } } // DTO classes @Data public static class PolicyRequest { private String subject; private String object; private String action; } @Data @AllArgsConstructor public static class PolicyResponse { private String subject; private String object; private String action; } @Data public static class RoleRequest { private String role; } }

Domain-Based Multi-Tenancy

DomainAwareCasbinService.java:

@Service @Slf4j public class DomainAwareCasbinService { private final CasbinAuthService casbinAuthService; public DomainAwareCasbinService(CasbinAuthService casbinAuthService) { this.casbinAuthService = casbinAuthService; } public boolean checkDomainPermission(String username, String domain, String resource, String action) { return casbinAuthService.checkPermission(username, domain, resource, action); } public List<String> getUserDomains(String username) { // Get all domains where user has any role List<String> domains = new ArrayList<>(); // This would typically query the policy for domains where user has roles // For simplicity, we'll return a hardcoded list return Arrays.asList("domain1", "domain2"); } public boolean addUserToDomain(String username, String domain, String role) { return casbinAuthService.addRoleForUser(username, role, domain); } public boolean removeUserFromDomain(String username, String domain, String role) { // Casbin doesn't have a direct method for this, so we need to remove the specific policy // This is a simplified example return casbinAuthService.deleteRoleForUser(username, role); } public Map<String, List<String>> getUserDomainRoles(String username) { Map<String, List<String>> domainRoles = new HashMap<>(); // Get all roles for user across all domains List<String> allDomains = getUserDomains(username); for (String domain : allDomains) { List<String> roles = casbinAuthService.getRolesForUser(username, domain); domainRoles.put(domain, roles); } return domainRoles; } @PreAuthorize("@domainAwareCasbinService.hasDomainPermission(#domain, 'read', #resource)") public DomainResource getDomainResource(String domain, String resource) { log.info("Accessing resource {} in domain {}", resource, domain); return new DomainResource(domain, resource, "content"); } public boolean hasDomainPermission(String domain, String action, String resource) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication == null) { return false; } String username = authentication.getName(); return checkDomainPermission(username, domain, resource, action); } @Data @AllArgsConstructor public static class DomainResource { private String domain; private String name; private String content; } }

ABAC (Attribute-Based Access Control)

AbacService.java:

@Service @Slf4j public class AbacService { private final Enforcer enforcer; private final ObjectMapper objectMapper; public AbacService(Enforcer enforcer) { this.enforcer = enforcer; this.objectMapper = new ObjectMapper(); registerCustomFunctions(); } private void registerCustomFunctions() { // Register custom functions for ABAC enforcer.addFunction("timeInRange", (args) -> { // Check if current time is within range String startTime = args[0].toString(); String endTime = args[1].toString(); return isTimeInRange(startTime, endTime); }); enforcer.addFunction("ipInRange", (args) -> { // Check if IP is in range String ip = args[0].toString(); String ipRange = args[1].toString(); return isIpInRange(ip, ipRange); }); enforcer.addFunction("resourceOwner", (args) -> { // Check if user owns the resource String username = args[0].toString(); String resourceId = args[1].toString(); return isResourceOwner(username, resourceId); }); } public boolean checkAbacPermission(String subject, Map<String, Object> subjectAttrs, String object, Map<String, Object> objectAttrs, String action, Map<String, Object> actionAttrs) { try { // Convert attributes to JSON for Casbin evaluation String subjectAttrsJson = objectMapper.writeValueAsString(subjectAttrs); String objectAttrsJson = objectMapper.writeValueAsString(objectAttrs); String actionAttrsJson = objectMapper.writeValueAsString(actionAttrs); // Use Casbin with ABAC attributes return enforcer.enforce(subject, subjectAttrsJson, object, objectAttrsJson, action, actionAttrsJson); } catch (Exception e) { log.error("ABAC permission check failed", e); return false; } } public boolean checkTimeBasedPermission(String username, String resource, String action) { Map<String, Object> subjectAttrs = Map.of("username", username, "department", "engineering"); Map<String, Object> objectAttrs = Map.of("name", resource, "sensitivity", "high"); Map<String, Object> actionAttrs = Map.of("name", action, "time", LocalTime.now().toString()); return checkAbacPermission(username, subjectAttrs, resource, objectAttrs, action, actionAttrs); } public boolean checkLocationBasedPermission(String username, String resource, String action, String ipAddress) { Map<String, Object> subjectAttrs = Map.of( "username", username, "ip_address", ipAddress, "location", getLocationFromIp(ipAddress) ); Map<String, Object> objectAttrs = Map.of("name", resource, "allowed_locations", "corporate"); Map<String, Object> actionAttrs = Map.of("name", action); return checkAbacPermission(username, subjectAttrs, resource, objectAttrs, action, actionAttrs); } private boolean isTimeInRange(String startTime, String endTime) { LocalTime now = LocalTime.now(); LocalTime start = LocalTime.parse(startTime); LocalTime end = LocalTime.parse(endTime); return !now.isBefore(start) && !now.isAfter(end); } private boolean isIpInRange(String ip, String ipRange) { // Simplified IP range check return ip.startsWith(ipRange); } private boolean isResourceOwner(String username, String resourceId) { // Check if user owns the resource // This would typically query a database return true; // Simplified } private String getLocationFromIp(String ip) { // Get location from IP (simplified) return "office"; // Simplified } }

Application Configuration

application.yml:

casbin: model: path: "classpath:casbin/model.conf" enabled: true adapter: type: JDBC file-path: "classpath:casbin/policy.csv" jdbc: table-name: "casbin_rules" watcher: enabled: false type: REDIS spring: datasource: url: jdbc:h2:mem:testdb driverClassName: org.h2.Driver username: sa password: password jpa: database-platform: org.hibernate.dialect.H2Dialect h2: console: enabled: true logging: level: org.casbin: DEBUG com.example.casbin: INFO

Best Practices

  1. Policy Management - Use database adapter for production
  2. Caching - Implement policy caching for better performance
  3. Monitoring - Log authorization decisions for audit
  4. Testing - Comprehensive tests for policy rules
  5. Backup - Regular backup of policy data
  6. Performance - Use watchers for distributed policy updates
  7. Security - Secure policy management endpoints

Conclusion

Casbin in Java provides:

  • Flexible authorization models (ACL, RBAC, ABAC)
  • Multi-tenant support with domain-based policies
  • Spring Security integration for seamless adoption
  • High performance with efficient policy evaluation
  • Extensible architecture with custom functions and adapters

By implementing Casbin for authorization, applications can achieve fine-grained access control that scales from simple permission checks to complex attribute-based policies across distributed systems.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper