Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ using an RwLock like so: `let e = Arc::new(RwLock::new(e));`.
- [Documentation](#documentation)
- [Online editor](#online-editor)
- [Tutorials](#tutorials)
- [Multiple Section Types](#multiple-section-types)
- [Policy management](#policy-management)
- [Policy persistence](#policy-persistence)
- [Role manager](#role-manager)
Expand Down Expand Up @@ -172,6 +173,51 @@ You can also use the online editor (http://casbin.org/editor/) to write your cas

https://casbin.org/docs/tutorials

## Multiple Section Types

Casbin-rs supports models with multiple policy and request sections (e.g., `p2`, `r2`, `m2`, `e2`). This allows you to define different sets of policies and matchers for different types of authorization checks within the same model. See the [documentation](https://casbin.org/docs/syntax-for-models#multiple-section-types) for more details.

To use multiple section types, define them in your model:

```ini
[request_definition]
r = sub, act, obj
r2 = sub, act

[policy_definition]
p = sub, act, obj
p2 = sub, act

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

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

Then use `EnforceContext` to specify which section to enforce:

```rust
use casbin::prelude::*;
use casbin::EnforceContext;

#[tokio::main]
async fn main() -> Result<()> {
let e = Enforcer::new("examples/multi_section_model.conf", "examples/multi_section_policy.csv").await?;

// Use default section (p, r, m, e)
e.enforce(("alice", "read", "project1"))?;

// Use second section (p2, r2, m2, e2)
let ctx2 = EnforceContext::new("2");
e.enforce_with_context(ctx2, ("james", "execute"))?;

Ok(())
}
```

## Policy management

casbin-rs provides two sets of APIs to manage permissions:
Expand Down Expand Up @@ -209,6 +255,7 @@ ABAC | [abac_model.conf](https://github.com/casbin/casbin-rs/blob/master/example
RESTful | [keymatch_model.conf](https://github.com/casbin/casbin-rs/blob/master/examples/keymatch_model.conf) | [keymatch_policy.csv](https://github.com/casbin/casbin-rs/blob/master/examples/keymatch_policy.csv)
Deny-override | [rbac_model_with_deny.conf](https://github.com/casbin/casbin-rs/blob/master/examples/rbac_with_deny_model.conf) | [rbac_policy_with_deny.csv](https://github.com/casbin/casbin-rs/blob/master/examples/rbac_with_deny_policy.csv)
Priority | [priority_model.conf](https://github.com/casbin/casbin-rs/blob/master/examples/priority_model.conf) | [priority_policy.csv](https://github.com/casbin/casbin-rs/blob/master/examples/priority_policy.csv)
Multiple Section Types | [multi_section_model.conf](https://github.com/casbin/casbin-rs/blob/master/examples/multi_section_model.conf) | [multi_section_policy.csv](https://github.com/casbin/casbin-rs/blob/master/examples/multi_section_policy.csv)

## Middlewares

Expand Down
68 changes: 68 additions & 0 deletions src/enforcer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1962,4 +1962,72 @@ m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
}

#[cfg(not(target_arch = "wasm32"))]
#[cfg_attr(
all(feature = "runtime-async-std", not(target_arch = "wasm32")),
async_std::test
)]
#[cfg_attr(
all(feature = "runtime-tokio", not(target_arch = "wasm32")),
tokio::test
)]
async fn test_multi_section_model() {
let m = DefaultModel::from_file("examples/multi_section_model.conf")
.await
.unwrap();

let adapter =
FileAdapter::new("examples/multi_section_policy.csv");
let mut e = Enforcer::new(m, adapter).await.unwrap();

// Test the default section (p, r, m, e)
assert_eq!(true, e.enforce(("alice", "read", "project1")).unwrap());
assert_eq!(
true,
e.enforce(("alice", "write", "project1")).unwrap()
);
assert_eq!(false, e.enforce(("alice", "read", "project2")).unwrap());
assert_eq!(true, e.enforce(("bob", "read", "project2")).unwrap());
assert_eq!(false, e.enforce(("bob", "write", "project2")).unwrap());

// Test the second section (p2, r2, m2, e2) using EnforceContext
assert_eq!(
true,
e.enforce_with_context(
EnforceContext::new("2"),
("james", "execute")
)
.unwrap()
);
assert_eq!(
false,
e.enforce_with_context(
EnforceContext::new("2"),
("james", "write")
)
.unwrap()
);

// Test that we can add policies to p2 section
e.add_named_policy(
"p2",
vec!["alice".to_string(), "write".to_string()],
)
.await
.unwrap();

// Rebuild role links after adding policies
e.build_role_links().unwrap();

// Verify the new p2 policy works
assert_eq!(
true,
e.enforce_with_context(
EnforceContext::new("2"),
("alice", "write")
)
.unwrap()
);
}
}