安全访问控制管理框架 - jCasbin

jCasbin是一款访问控制框架,拥有丰富的访问控制模型(Computer security model),支持多种主流语言。

casbin

开发语言支持

Go语言版casbin、Java语言版jcasbin

Node语言版node-casbin、php语言版PHP-Casbin

python语言版PyCasbin、pascal语言版Casbin4D

Net语言版Casbin-Net、Rust语言版casbin-rs

功能

1.按照经典表单{subject, object, action},或自定义表单执行定义的策略,支持[允许]和[拒绝]两种授权。

2.处理访问控制模型及其策略的存储。

3.管理角色 - 用户映射和角色 - 角色映射(RBAC的角色层级结构)。

4.内置超级用户,如:root、administrator。超级用户默认能做任何事。

5.内置多个操作符,支持规则匹配。如:keyMatch将资源/foo/bar映射到/foo*。

不能做什么

1.不负责身份验证。

Casbin不负责用户登录信息验证(用户登录时username、password验证)。

2.不负责管理用户或角色列表。

Casbin相信由项目自身管理这些实体会更方便。

用户通常拥有自己的密码,而Casbin并非为密码容器而设计。Casbin会存储RBAC方案的中用户与角色的映射。

若确实需要Casbin验证和授权,可加入Casbin,GO语言编写的简单API网关

依赖

<dependency>
  <groupId>org.casbin</groupId>
  <artifactId>jcasbin</artifactId>
  <version>1.2.0</version>
</dependency>

安装方式详见Casbin安装手册

入门

最新版的Casbin执行器,能直接读取模型文件和策略文件:

import org.casbin.jcasbin.main.Enforcer;

Enforcer enforcer = new Enforcer("path/to/model.conf", "path/to/policy.csv");

也能够从数据库中读取数据。在访问前加入如下处理逻辑:

String sub = "alice"; // the user that wants to access a resource.
String obj = "data1"; // the resource that is going to be accessed.
String act = "read"; // the operation that the user performs on the resource.

if (enforcer.enforce(sub, obj, act) == true) {
    // permit alice to read data1
} else {
    // deny the request, show an error
}

除静态策略文件,Casbin还提供运行时权限管理API。如,分配给用户的角色:

Roles roles = enforcer.getRoles("alice");

权限管理API

Casbin权限管理API目前只支持Go语言和Node.js。

具体参考Casbin权限管理API

权限配置参考在线编辑工具

多线程处理

多线程方式使用Casbin,可使用Casbin enforcer的同步包装类

它支持AutoLoad功能,若发生变更,Casbin enforcer自动从DB加载最新策略。

StartAutoLoadPolicy():定期加载策略。

StopAutoLoadPolicy():停止操作。

管理界面

casbin ui policy editor

参见Casbin web-ui

安全模型

Casbin支持多达11种的安全模型。

具体配置参考Casbin模型示例,稍后会列出支持的11种安全控制模型

模型语法

Casbin CONF模型包含四个部分:

[request_definition]、[policy_definition]、[policy_effect]、[matchers]。

使用RBAC模型,还需添加[role_definition]部分。

CONF模型可以包含注释(#)。

# Request definition
[request_definition]
r = sub, obj, act

# Policy definition
[policy_definition]
p = sub, obj, act

# Policy effect

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

# Matchers
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

详情参见Casbin模型语法

日志处理

Casbin内置log,默认启用日志记录。格式如下:

2017/07/15 19:43:56 [Request: alice, data1, read ---> true] 

使用Enforcer.EnableLog()或NewEnforcer()的最后一个参数切换它:

// Disable the logging in the new method.
e := casbin.NewEnforcer("examples/basic_model.conf", "examples/basic_policy.csv", false)

// Enable the logging at run-time.
e.EnableLog(true)

详情参见Casbin日志处理

11种安全模型

ACL(访问控制列表)

ACL和超级用户

没有用户的ACL:对没有身份验证或用户登录的系统尤其有用。

没有资源的ACL:通过使用write-article、read-log等权限。适用针对一种资源类型,而不是单个资源的场景。不控制对特定文章或日志的访问。

RBAC:基于角色的访问控制

具有资源角色的RBAC:用户和资源能同时拥有角色(或组)。

具有域/租户的RBAC:对于不同的域/租户,用户可以拥有不同的角色集。

基于属性的访问控制(ABAC):类似资源的语法糖。所有者可用于获取资源属性。

RESTful:支持/res/*、/res/:id等路径和GET、POST、PUT、DELETE等HTTP方法。

拒绝覆盖(Deny-override):支持允许和拒绝授权,拒绝覆盖允许。

优先级(Priority):策略规则像防火墙规则一样优先级化。

工作原理

以Java版Casbin为例,说明Casbin工作原理。

在jCasbin中,访问控制模型基于PERM元模型(策略、效果、请求、匹配器)抽象的CONF文件。

切换或升级项目的授权机制,如同修改配置一样简单。

通过组合可用的模型,自定义个性化的访问控制模型。

如:在一个模型中将RBAC角色和ABAC属性放在一起,并共享一组策略规则。

ACL模型

p, alice, data1, read
p, bob, data2, write

示例中表示alice可以访问data1,bob可以对data2进行写操作。

PERM元模型

PERM(策略、效果、请求、匹配器)的实例描述四种实体如何交互以完成授权。

首先了解一下相关概念,再看一个示例模型。

请求(Request)

有关访问请求的信息。

一个请求会包含一组subject、action、resource数据,r = {sub, action, resource}。逻辑实体构建于持久数据之上,就像CRM系统中的客户一样。

策略(Policy)

构成系统规则的模型,如:允许管理员读取用户信息

p = {sub, action, resource}

匹配器(Matchers)

请求和策略如何匹配的模型。

最简单的例子是使用等式匹配请求和策略。

m = r.sub == p.sub && r.action == p.action && r.resource == p.resource

效果(Effect)

将组合或拆分的策略模型去请求得以一个最终结果。

评估表达式的值可在每个策略的eft字段中找到。

e = some(p.eft == allow)

下图中演示了如何基于PERM模型作授权请求。

perm

ACL授权模型定义

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act

这种授权模型,定义授权规则的策略如下:

p, alice, data1, read
p, bob, data2, write

允许admin用户访问所有内容的定义如下:

[matchers]
m = r.sub == admin || (r.sub == p.sub && r.obj == p.obj && r.act == p.act)

启用基于简单属性的访问控制,访问resource对象中的数据。

如果只允许资源所有者发起的请求,匹配器表达式将改为:

m = r.obj.owner == r.sub && (r.sub == p.sub && r.obj == p.obj && r.act == p.act)