Most applications eventually run into authorization and permission management. Sometimes you want something you can plug into a small personal project without much setup, but that can also scale to more complicated rules in a larger system. Casbin fits that role well. It supports multiple programming languages, and in Python, PyCasbin is straightforward enough to get running with only a few files.

What Casbin is

Casbin is an open-source access control library built to enforce authorization rules efficiently. Its main strength is that it supports multiple access control models, so it is not limited to a single way of describing permissions.

Installing PyCasbin

First install the Python package:

pip install casbin

Besides the library itself, a basic setup also needs two configuration files: model.conf and policy.csv.

  • model.conf defines the access control model.
  • policy.csv stores the actual permission rules for users.

A minimal Python script can load both files like this:

import casbin
import os

# model.conf 和 policy.csv 文件地址
model_dir = os.path.join(os.path.dirname(__file__), 'model.conf')
policy_dir = os.path.join(os.path.dirname(__file__), 'policy.csv')

# 加载配置文件
e = casbin.Enforcer(model_dir,policy_dir)

A simple ACL model

In this example, model.conf contains an ACL-style configuration:

[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

This model is very direct:

  • sub is the subject, usually the user
  • obj is the object or resource being accessed
  • act is the action performed on that resource

The matching rule requires all three values to line up exactly with a policy entry.

Defining permissions with policy.csv

The policy file can contain rules such as:

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

That means:

  • alice can read data1
  • bob can write data2

Testing permissions in Python

Once the model and policy are in place, permission checks are just a call to the enforcer. The full example script looks like this:

import casbin
import os

# model.conf 和 policy.csv 文件地址
model_dir = os.path.join(os.path.dirname(__file__), 'model.conf')
policy_dir = os.path.join(os.path.dirname(__file__), 'policy.csv')
# 加载配置文件
e = casbin.Enforcer(model_dir,policy_dir)
sub = "alice"  # 想要访问资源的用户
obj = "data1"  # 将要被访问的资源
act = "read"  # 用户对资源进行的操作

def getEnforce(sub, obj, act):
    """
    执行器的封装
    """
    if e.enforce(sub, obj, act):
        # 允许alice读取data1
        return True
    else:
        # 拒绝请求,抛出异常
        return False

if __name__ == '__main__':
    print(getEnforce(sub,obj,act))

Running this script prints True, because the policy allows alice to read data1. The example is simple enough that the comments already explain most of what is happening: load the model, load the policy, then ask the enforcer whether a request should be allowed.

Storing policies in a database

Keeping policies in a flat file is useful for a quick start, but real applications often need something closer to production usage. A database-backed policy store is usually more practical.

For that, you can use casbin_sqlalchemy_adapter, which wraps a lot of the database-related Casbin operations so you do not have to build them yourself.

Install it with:

pip install casbin_sqlalchemy_adapter

After that, replace the policy.csv path with a database adapter. The first part of test.py becomes:

# model.conf 和 policy.csv 文件地址
model_dir = os.path.join(os.path.dirname(__file__), 'model.conf')
# policy_dir = os.path.join(os.path.dirname(__file__), 'policy.csv')
# 组装数据库的绝对地址
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_DIR = os.path.join(BASE_DIR, 'test.db')
# 数据库访问地址
SQLALCHEMY_DATABASE_URL = "sqlite:///" + DB_DIR
# 从数据库加载casbin的policy
adapter = casbin_sqlalchemy_adapter.Adapter(SQLALCHEMY_DATABASE_URL)
e = casbin.Enforcer(model_dir, adapter)
e.add_policy(["alice", "data1", "read"])

Here the file-based policy path is commented out and replaced with a database connection. When the program runs, it creates a database and a table named casbin_rule. The contents of that table correspond to the same kind of rules you would otherwise place in policy.csv.

Policies can be added with e.add_policy(), and the adapter also supports the usual management operations such as adding multiple rules, updating them, or deleting them.

Once this change is made, the permission check behaves the same way as it did with the CSV file, but the policies are now stored in a database instead. That makes the setup much more practical for actual applications.

Casbin is not limited to this ACL example either. It can support other permission models such as RBAC. Even from a small example like this, it is easy to see why it is a handy framework: the setup is uncomplicated, the behavior is clear, and it removes a lot of repetitive authorization work.