关于springboot整合Jcasbin权限校验说明
1. Casbin简介使用文档1.1Casbin 是什么?Casbin 可以:支持自定义请求的格式,默认的请求格式为{subject, object, action}。具有访问控制模型model和策略policy两个核心概念。支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。支持内置的超级用户 例如:root或administrator。超级用户可以执行任何操作而无需显式的权限
·
1. Casbin简介
1.1Casbin 是什么?
- Casbin 可以:
- 支持自定义请求的格式,默认的请求格式为{subject, object, action}。
- 具有访问控制模型model和策略policy两个核心概念。
- 支持RBAC中的多层角色继承,不止主体可以有角色,资源也可以具有角色。
- 支持内置的超级用户 例如:root或administrator。超级用户可以执行任何操作而无需显式的权限声明。
- 支持多种内置的操作符,如 keyMatch,方便对路径式的资源进行管理,如 /foo/bar 可以映射到 /foo*
- Casbin 不能:
- 身份认证 authentication(即验证用户的用户名、密码),casbin只负责访问控制。应该有其他专门的组件负责身份认证,然后由casbin进行访问控制,二者是相互配合的关系。
- 管理用户列表或角色列表。 Casbin 认为由项目自身来管理用户、角色列表更为合适, 用户通常有他们的密码,但是 Casbin 的设计思想并不是把它作为一个存储密码的容器。 而是存储RBAC方案中用户和角色之间的映射关系。
1.2 API文档
2. Casbin使用
2.1 引入依赖
<dependency>
<groupId>org.casbin</groupId>
<artifactId>jcasbin</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.casbin</groupId>
<artifactId>jdbc-adapter</artifactId>
<version>2.0.0</version>
</dependency>
2.2 Model文件
支持的Models
- ACL (Access Control List, 访问控制列表)
- 具有 超级用户 的 ACL
- 没有用户的 ACL: 对于没有身份验证或用户登录的系统尤其有用。
- 没有资源的 ACL: 某些场景可能只针对资源的类型, 而不是单个资源, 诸如 write-article, read-log等权限。 它不控制对特定文章或日志的访问。
- RBAC (基于角色的访问控制)
- 支持资源角色的RBAC: 用户和资源可以同时具有角色 (或组)。
- 支持域/租户的RBAC: 用户可以为不同的域/租户设置不同的角色集。
- ABAC (基于属性的访问控制): 支持利用resource.Owner这种语法糖获取元素的属性。
- RESTful: 支持路径, 如 /res/*, /res/: id 和 HTTP 方法, 如 GET, POST, PUT, DELETE。
- 拒绝优先: 支持允许和拒绝授权, 拒绝优先于允许。
- 优先级: 策略规则按照先后次序确定优先级,类似于防火墙规则。
权限校验将根据matchers进行校验,注意matchers写法
,下面是一个具有超级管理员admin
权限的Model文件。
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act || r.sub == "admin"
RESTFu与RBAC共同使用
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = r.sub == p.sub && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act) || g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act || g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)
2.3 Policy 文件
Policy文件可用使用scv
文件,也可以使用JDBC
数据库形式,详细参考
3. 使用方法
3.1 编写一个配置类,读取jdbc配置
@Data
@Configuration
@ConfigurationProperties(prefix = "org.jcasbin")
public class EnforcerConfigProperties {
private String datasourceUrl;
private String driverClassName;
private String datasourceUserName;
private String databasePassword;
@Bean
public JDBCAdapter jdbcAdapter() throws Exception {
return new JDBCAdapter(driverClassName, datasourceUrl, datasourceUserName,databasePassword );
}
}
配置文件 application.properties
org.jcasbin.url=jdbc:mysql://localhost:3306/test
org.jcasbin.driver-class-name=com.mysql.cj.jdbc.Driver
org.jcasbin.username=root
org.jcasbin.password=root
3.2 也可以使用springjdbc配置
@Configuration
@Slf4j
public class CasbinAdapterConfiguration {
/**
* datasourceUrl 连接数据库url
*/
@Value("${spring.datasource.url}")
private String datasourceUrl;
/**
* driverClassName 数据库驱动
*/
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
/**
* datasourceUserName 连接数据库的用户名
*/
@Value("${spring.datasource.username}")
private String datasourceUserName;
/**
* databasePassword 连接数据库密码
*/
@Value("${spring.datasource.password}")
private String databasePassword;
@Bean
public JDBCAdapter jdbcAdapter() throws Exception {
return new JDBCAdapter(driverClassName, datasourceUrl, datasourceUserName,databasePassword );
}
}
3.3 创建Policy
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Policy {
/**
* 想要访问资源的用户 或者角色
*/
private String sub;
/**
* 将要访问的资源,可以使用 * 作为通配符,例如/user/*
*/
private String obj;
/**
* 用户对资源执行的操作。HTTP方法,GET、POST、PUT、DELETE等,可以使用 * 作为通配符
*/
private String act;
}
3.4 创建Group
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Group {
/**
* 请求对象
*/
private String rSub;
/**
* 策略对象
*/
private String pSub;
}
3.5 创建一个EnforcerFactory
@Component
public class EnforcerFactory implements InitializingBean {
private Enforcer enforcer;
private EnforcerConfigProperties enforcerConfigProperties;
private JDBCAdapter jdbcAdapter;
@Autowired
public EnforcerFactory(EnforcerConfigProperties enforcerConfigProperties,JDBCAdapter jdbcAdapter) {
this.enforcerConfigProperties = enforcerConfigProperties;
this.jdbcAdapter = jdbcAdapter;
}
@Override
public void afterPropertiesSet() throws Exception {
enforcerConfigProperties = enforcerConfigProperties;
//从数据库读取策略
Model model = new Model();
File file = new File("src/main/resources/conf/authz_model.conf");
String canonicalPath = file.getCanonicalPath();
model.loadModel(canonicalPath);
enforcer = new Enforcer(model, jdbcAdapter);
}
/**
* 添加权限
*
* @param policy
* @return
*/
public boolean addPolicy(Policy policy) {
boolean addPolicy = enforcer.addPolicy(policy.getSub(), policy.getObj(), policy.getAct());
enforcer.savePolicy();
return addPolicy;
}
/**
* 删除权限
*
* @param policy
* @return
*/
public boolean removePolicy(Policy policy) {
boolean removePolicy = enforcer.removePolicy(policy.getSub(), policy.getObj(), policy.getAct());
enforcer.savePolicy();
return removePolicy;
}
public Enforcer getEnforcer() {
return enforcer;
}
}
3.6 自定义一个过滤器/拦截器
ublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
System.out.println("过滤器初始化");
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String user = request.getParameter("username");
String path = request.getRequestURI();
String method = request.getMethod();
if (path.contains("anon")) {
chain.doFilter(request, response);
}else if (enforcer.enforce(user, path, method)) {
chain.doFilter(request, response);
} else {
log.info("无权访问");
Map<String, Object> result = new HashMap<String, Object>();
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));
}
}
@Override
public void destroy() {
}
}
3.7 创建一个controller
@RestController
public class contorller {
@Autowired
private EnforcerFactory enforcerFactory;
@GetMapping("/anon/test")
public void Test(){
enforcerFactory.addPolicy(new Policy("alice", "/test", "GET"));
}
@GetMapping("/test")
public void test1(){
System.out.println("通过");
}
}
3.8 测试
4. CasbinAPI使用
5. demo下载
6.扩展
6.1 Model文件编辑测试
6.2 Springboot整合Jcasbin
casbin-spring-boot-starter源码,修改力度大,功能不完善,可参考
<!-- https://mvnrepository.com/artifact/org.casbin/casbin-spring-boot-starter -->
<dependency>
<groupId>org.casbin</groupId>
<artifactId>casbin-spring-boot-starter</artifactId>
<version>0.0.11</version>
</dependency>
7. 常见问题
7.1 FileNotFoundException
springboot打成jar后,启动时抛出Caused by: java.io.FileNotFoundException: class path resource [model.conf] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/opt/fabric-apps/fabric-mgt/target/fabric-mgt.jar!/BOOT-INF/classes!/model.conf
解决方案
更多推荐
已为社区贡献9条内容
所有评论(0)