Integrating jCasbin Permission Management into Spring Boot Applications
This article explains how backend developers can replace Shiro with jCasbin for permission management in Spring Boot projects, covering Maven dependencies, configuration files, property loading, Enforcer initialization, custom policy objects, request filtering, and dynamic policy updates.
As a backend developer, the article introduces jCasbin as an alternative to Shiro for permission management in Spring Boot projects.
It first shows how to add the required 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 roles and permissions in two configuration files, model.conf and policy.csv , and can also load them from a database. An example application.properties configuration is provided:
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.confA EnforcerConfigProperties class is defined to bind these properties, and an EnforcerFactory implements InitializingBean to create a static Enforcer instance using the model file and a JDBCAdapter that reads policies from the database.
@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; }
}The Policy POJO encapsulates the three fields required by jCasbin: sub (subject), obj (object), and act (action).
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 + "]";
}
}For runtime permission checks, a web filter ( JCasbinAuthzFilter ) extracts the username, request path, and HTTP method, then calls enforcer.enforce(user, path, method) . If the check fails, a JSON error response is returned.
@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 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")) {
chain.doFilter(request, response);
} else if (enforcer.enforce(user, path, method)) {
chain.doFilter(request, response);
} else {
log.info("无权访问");
Map
result = new HashMap<>();
result.put("code", 1001);
result.put("msg", "用户权限不足");
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 how to add or delete policies 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 article concludes that jCasbin can be combined with Spring Cloud Zuul to achieve unified login and permission control across micro‑services.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
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.