How to Integrate jCasbin Permission Management into Spring Boot Applications
This tutorial explains how backend developers can replace Shiro with jCasbin for fine‑grained permission control in Spring Boot projects, covering Maven setup, configuration files, Enforcer initialization, custom filters, and dynamic policy management.
Introduction
As a backend developer, permission management is familiar, but Shiro has many drawbacks in distributed, front‑back separation scenarios. jCasbin offers a simpler alternative that can be quickly adopted.
1. Preparation
Based on Spring Boot, add the following Maven dependencies:
<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>2. Configuration Files
jCasbin stores roles and permissions in model.conf and policy.csv. Example application.properties configuration:
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. Initialize Permission Information
Create a class that implements InitializingBean to load the Enforcer with a JDBCAdapter and the model file.
@Component
public class EnforcerFactory implements InitializingBean {
private static Enforcer enforcer;
@Autowired
private EnforcerConfigProperties enforcerConfigProperties;
private static EnforcerConfigProperties config;
@Override
public void afterPropertiesSet() throws Exception {
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;
}
}Define a simple Policy class to encapsulate sub, obj, and act fields.
public class Policy {
/** User or role */
private String sub;
/** Resource, supports * wildcard */
private String obj;
/** Action (HTTP method), supports * wildcard */
private String act;
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 + "]";
}
}4. Usage
Permission Control
Create a servlet filter that checks permissions using enforcer.enforce(user, path, method). If the check fails, return a JSON error response.
@WebFilter(urlPatterns = "/*", filterName = "JCasbinAuthzFilter")
@Order(Ordered.HIGHEST_PRECEDENCE)
public class JCasbinAuthzFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(JCasbinAuthzFilter.class);
private static Enforcer enforcer;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String user = request.getParameter("username");
String path = request.getRequestURI();
String method = request.getMethod();
enforcer = EnforcerFactory.getEnforcer();
if (path.contains("anon")) {
chain.doFilter(request, response);
} else if (enforcer.enforce(user, path, method)) {
chain.doFilter(request, response);
} else {
log.info("Access denied");
Map<String, Object> 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 methods omitted
}Add/Delete Permissions
Expose controller endpoints that call EnforcerFactory.addPolicy and EnforcerFactory.removePolicy to modify policies at runtime without restarting the service.
@PutMapping("/anon/role/per")
public ResultBO<Object> addPer() {
EnforcerFactory.addPolicy(new Policy("alice", "/user/list", "*"));
return ResultTool.success();
}
@DeleteMapping("/anon/role/per")
public ResultBO<Object> deletePer() {
EnforcerFactory.removePolicy(new Policy("alice", "/user/list", "*"));
return ResultTool.success();
}Conclusion
jCasbin can be combined with Spring Cloud Zuul to achieve unified login and permission control by extending ZuulFilter. The presented approach provides a lightweight, dynamic, and database‑driven permission system for Spring Boot backends.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.
