Simplify Spring Boot Permission Management with jCasbin

This guide shows how to replace Shiro with jCasbin in a Spring Boot microservice, covering Maven dependencies, configuration files, Enforcer initialization, policy handling, and a custom filter for runtime permission checks, enabling dynamic role‑based access control without server restarts.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Simplify Spring Boot Permission Management with jCasbin

Preface

As a backend developer, permission management is familiar; Java has public, private, etc. Shiro is powerful but cumbersome in distributed Spring Cloud projects, requiring many customizations. jCasbin offers a lightweight alternative that can be quickly integrated.

1. Preparation

The example uses Spring Boot 1.5.10, but any version works.

1. Maven Dependency

<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 role‑permission mappings in model.conf and policy.csv. These files can also be loaded from a database.

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

2. Initialize Enforcer

Create a configuration properties class and a factory that implements InitializingBean to load the policy at startup.

@Configuration
@ConfigurationProperties(prefix = "org.jcasbin")
public class EnforcerConfigProperties {
    private String url;
    private String driverClassName;
    private String username;
    private String password;
    private String modelPath;
    // getters and setters omitted for brevity
    @Override
    public String toString() {
        return "EnforcerConfigProperties [url=" + url + ", driverClassName=" + driverClassName + ", username=" + username + ", password=" + password + ", modelPath=" + modelPath + "]";
    }
}
@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(); // Load the policy from DB.
    }
    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;
    }
}

Policy POJO

public class Policy {
    /** User or role that wants to access a resource */
    private String sub;
    /** Resource, can use * as wildcard, e.g., /user/* */
    private String obj;
    /** Action, HTTP method, can use * as 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 + "]";
    }
}

3. Usage

1. Permission Control

Implement a servlet filter that uses enforcer.enforce(user, path, method) to decide whether to allow the request.

@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 omitted for brevity
}

2. Add / Remove Permissions

Expose REST endpoints that call the factory methods to modify policies at runtime; changes take effect immediately 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

Combining jCasbin with Spring Cloud (e.g., Zuul) enables unified login and fine‑grained permission control. By defining a custom filter or extending ZuulFilter, you can integrate dynamic RBAC into any microservice architecture.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaSpring Bootpermission managementjCasbin
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

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.