Casbin Forum runs on Casnode, the open-source Discourse-style forum. Try the Casnode demo →
Casbin Forum

Finally:

p, 1, /something, GET, sol-*

Why if there are zero groups does it pass. There should be nothing to match right?
But if I do:

p, r1, /something, GET, sol-*

It again gives false as it should be

Yes I believe they do but generally you can also just load it one time and keep it in memory

I want to understand how it will integrate with my application.

I will check it out

Is there a free trial or hobby project version that can be used?

Not the most efficient but gaurantee that I get the latest data

Yeah currently not worrying about perfomance

I am not using the default structure like in this adapter:
https://github.com/casbin/xorm-adapter

So I can gather the data I need efficiently and generate the policy + role group at runtime

My example is just an example to make it understandable. In the end it will all just be id's that are matched

In my case only the model is static all others things are loaded from db or cache at runtime per request

Yeah same

customers can create their own roles with their own permissions

I went from this model:

const stringModel = `
[request_definition]
r = user, dom, obj, act, tag

[policy_definition]
p = role, dom, obj, act, tag

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

[role_definition]
g = _, _, _
g2 = _, _

[matchers]
m = g(r.user, p.role, r.tag) && g2(p.role, r.dom) && keyMatch(r.tag, p.tag) && keyMatch(r.act, p.act) && (keyMatch(r.obj, p.obj) || keyMatch2(r.obj, p.obj))
    `

func TestDefaultRbac(t *testing.T) {
    m, _ := model.NewModelFromString(stringModel)
    e, _ := casbin.NewEnforcer(m, false)

    e.AddPolicies([][]string{
        {"reader", "org1", "/project", "GET", "project_*"},
        {"editor", "org1", "/project", "DELETE", "project_*"},
        {"reader2", "org2", "/project", "GET", "project_*"},
    })

    e.AddNamedGroupingPolicies("g", [][]string{
        {"tom", "reader", "project_1"},
        {"tom", "reader", "project_2"},
        {"tom", "reader", "project_3"},
        {"tom", "editor", "project_5"},
        {"henk", "reader2", "project_6"},
    })

    e.AddNamedGroupingPolicies("g2", [][]string{
        {"reader", "org1"},
        {"reader2", "org2"},
        {"editor", "org1"},
    })

    enforcer := func(user, dom, obj, act, tag string, expect bool) {
        resp, _ := e.Enforce(user, dom, obj, act, tag)
        if resp != expect {
            t.Errorf("Response is for %s %s %s %s %s %t expected to be %t", user, dom, obj, act, tag, resp, expect)
        }
    }

    enforcer("tom", "org1", "/project", "GET", "project_1", true)
    enforcer("tom", "org1", "/project", "DELETE", "project_1", false)
    enforcer("tom", "org1", "/project", "DELETE", "project_5", true)
    enforcer("tom", "org2", "/project", "GET", "project_6", false)
    enforcer("henk", "org2", "/project", "GET", "project_6", true)
}

to this, I left out the whole org part since the roles will be unique per org and are therefore implicity tied to an org:


const stringModel2 = `
[request_definition]
r = user, obj, act, tag

[policy_definition]
p = role, obj, act, tag

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

[role_definition]
g = _, _, _

[matchers]
m = g(r.user, p.role, r.tag) && keyMatch(r.tag, p.tag) && keyMatch(r.act, p.act) && (keyMatch(r.obj, p.obj) || keyMatch2(r.obj, p.obj))
    `

func TestDefaultRbac2(t *testing.T) {
    m, _ := model.NewModelFromString(stringModel2)
    e, _ := casbin.NewEnforcer(m, false)

    e.AddPolicies([][]string{
        {"reader", "/project", "GET", "project_*"},
        {"editor", "/project", "DELETE", "project_*"},
        {"reader2", "/project", "GET", "project_*"},
    })

    e.AddNamedGroupingPolicies("g", [][]string{
        {"tom", "reader", "project_1"},
        {"tom", "reader", "project_2"},
        {"tom", "reader", "project_3"},
        {"tom", "editor", "project_5"},
        {"henk", "reader2", "project_6"},
    })

    enforcer := func(user, obj, act, tag string, expect bool) {
        resp, _ := e.Enforce(user, obj, act, tag)
        if resp != expect {
            t.Errorf("Response is for %s %s %s %s %t expected to be %t", user, obj, act, tag, resp, expect)
        }
    }

    enforcer("tom", "/project", "GET", "project_1", true)
    enforcer("tom", "/project", "DELETE", "project_1", false)
    enforcer("tom", "/project", "DELETE", "project_5", true)
    enforcer("tom", "/project", "GET", "project_6", false)
    enforcer("henk", "/project", "GET", "project_6", true)
}

Both do the same thing one is explicit with role + org combination and the other is implicit. E.g. reader is part of org1 and reader2 is part of org2

I plan to make a custom adapter https://casbin.org/docs/adapters/ that loads the filtered policy for each request and checks it.

that loads the filtered policy for each request and checks it. for endpoints that need it