Integrating jCasbin Permission Management into Spring Boot Applications
This article introduces jCasbin as a lightweight alternative to Shiro for permission management in Spring Boot, explains Maven setup, configuration files, Enforcer initialization, policy model definition, and demonstrates how to enforce, add, and delete permissions dynamically using filters and REST endpoints.
Introduction
As a backend developer, the author discusses the drawbacks of using Shiro for permission management in distributed Spring Cloud projects and introduces jCasbin as a lightweight alternative.
1. Preparation
Shows Maven dependencies for jCasbin and its JDBC adapter:
<dependency>
<groupId>org.casbin</groupId>
<artifactId>jcasbin</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>org.casbin</groupId>
<artifactId>jdbc-adapter</artifactId>
<version>1.1.0</version>
</dependency>The framework stores role‑permission mappings in model.conf and policy.csv , which can also be loaded from a database.
2. Configuration
A Spring @ConfigurationProperties class loads DB connection details and the model file path, and the following entries are added to application.properties :
org.jcasbin.url=jdbc:mysql://localhost:3306/casbin?useSSL=false
org.jcasbin.driver-class-name=com.mysql.jdbc.Driver
org.jcasbin.username=root
org.jcasbin.password=root
org.jcasbin.model-path=conf/authz_model.conf3. Initializing Enforcer
An EnforcerFactory implements InitializingBean to create a static Enforcer using a JDBCAdapter that reads policies from the database. It also provides static methods to add and remove policies.
@Component
public class EnforcerFactory implements InitializingBean {
private static Enforcer enforcer;
@Autowired
private EnforcerConfigProperties enforcerConfigProperties;
@Override
public void afterPropertiesSet() throws Exception {
EnforcerConfigProperties config = enforcerConfigProperties;
JDBCAdapter jdbcAdapter = new JDBCAdapter(config.getDriverClassName(), config.getUrl(), config.getUsername(), config.getPassword(), true);
enforcer = new Enforcer(config.getModelPath(), jdbcAdapter);
enforcer.loadPolicy();
}
public static boolean addPolicy(Policy policy) {
boolean added = enforcer.addPolicy(policy.getSub(), policy.getObj(), policy.getAct());
enforcer.savePolicy();
return added;
}
public static boolean removePolicy(Policy policy) {
boolean removed = enforcer.removePolicy(policy.getSub(), policy.getObj(), policy.getAct());
enforcer.savePolicy();
return removed;
}
public static Enforcer getEnforcer() { return enforcer; }
}4. Policy Model
A simple POJO represents a permission entry:
public class Policy {
private String sub; // user or role
private String obj; // resource (supports wildcard)
private String act; // action (GET, POST, etc.)
public Policy() {}
public Policy(String sub, String obj, String act) { this.sub = sub; this.obj = obj; this.act = act; }
// getters and setters omitted for brevity
@Override
public String toString() { return "Policy[sub=" + sub + ", obj=" + obj + ", act=" + act + "]"; }
}5. Usage
A servlet filter checks permissions with enforcer.enforce(user, path, method) and returns a JSON error when access is denied.
@WebFilter(urlPatterns = "/*", filterName = "JCasbinAuthzFilter")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class JCasbinAuthzFilter implements Filter {
private static Enforcer enforcer;
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String user = request.getParameter("username");
String path = request.getRequestURI();
String method = request.getMethod();
enforcer = EnforcerFactory.getEnforcer();
if (path.contains("anon") || enforcer.enforce(user, path, method)) {
chain.doFilter(request, response);
} else {
Map
result = new HashMap<>();
result.put("code", 1001);
result.put("msg", "User lacks permission");
result.put("data", null);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().write(JSONObject.toJSONString(result, SerializerFeature.WriteMapNullValue));
}
}
// init and destroy omitted
}Two REST endpoints demonstrate dynamic permission management without restarting the service:
@PutMapping("/anon/role/per")
public ResultBO
addPer() {
EnforcerFactory.addPolicy(new Policy("alice", "/user/list", "*"));
return ResultTool.success();
}
@DeleteMapping("/anon/role/per")
public ResultBO
deletePer() {
EnforcerFactory.removePolicy(new Policy("alice", "/user/list", "*"));
return ResultTool.success();
}Conclusion
The author notes that jCasbin can be combined with Spring Cloud Zuul to achieve unified login and permission control, which will be explored in future posts.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.