Backend Development 10 min read

Integrating jCasbin Permission Management into Spring Boot Applications

This article explains how to replace Shiro with jCasbin for permission management in Spring Boot, covering Maven dependency setup, configuration files, Enforcer initialization, custom policy handling, and a simple servlet filter for runtime authorization checks.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Integrating jCasbin Permission Management into Spring Boot Applications

As a backend developer, the author finds traditional permission frameworks like Shiro cumbersome, especially in distributed Spring Cloud environments, and introduces jCasbin as a lightweight alternative.

First, add the jCasbin and JDBC‑adapter dependencies to your Maven pom.xml :

<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>

Configure the model and policy files ( model.conf and policy.csv ) and expose the database connection properties in 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.conf

Create a configuration class EnforcerConfigProperties to bind these properties, then implement an EnforcerFactory that implements InitializingBean to instantiate the Enforcer with a JDBCAdapter and load the policy at startup.

@Component
public class EnforcerFactory implements InitializingBean {
    private static Enforcer enforcer;
    @Autowired
    EnforcerConfigProperties enforcerConfigProperties;
    @Override
    public void afterPropertiesSet() throws Exception {
        JDBCAdapter jdbcAdapter = new JDBCAdapter(
            enforcerConfigProperties.getDriverClassName(),
            enforcerConfigProperties.getUrl(),
            enforcerConfigProperties.getUsername(),
            enforcerConfigProperties.getPassword(), true);
        enforcer = new Enforcer(enforcerConfigProperties.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 POJO to hold sub , obj , and act fields.

public class Policy {
    private String sub;
    private String obj;
    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 + "]";
    }
}

Implement a servlet filter JCasbinAuthzFilter that retrieves the current user, request path, and HTTP method, then calls enforcer.enforce(user, path, method) to decide whether to allow the request or 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("Unauthorized access");
            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
}

Expose REST endpoints to add or delete policies at runtime 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();
}

The author notes that jCasbin can also be combined with Spring Cloud Zuul by extending ZuulFilter for unified login and permission control across microservices.

backendJavapermissionSpring BootauthorizationjCasbin
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.