rust-xacml
3
总安装量
3
周安装量
#57779
全站排名
安装命令
npx skills add https://github.com/huiali/rust-skills --skill rust-xacml
Agent 安装分布
codebuddy
3
trae-cn
3
trae
2
gemini-cli
2
antigravity
2
claude-code
2
Skill 文档
æ ¸å¿æ¨¡å¼
1. çç¥è¯ä¼°å¨
//! çç¥è¯ä¼°å¨
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
/// 请æ±ä¸ä¸æ
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RequestContext {
pub subject: Subject, // 主ä½
pub resource: Resource, // èµæº
pub action: String, // æä½
pub environment: HashMap<String, String>, // ç¯å¢
}
/// 主ä½
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Subject {
pub id: String,
pub roles: Vec<String>,
pub attributes: HashMap<String, String>,
}
/// èµæº
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Resource {
pub id: String,
pub r#type: String,
pub attributes: HashMap<String, String>,
}
/// å³çç»æ
#[derive(Debug, Clone, PartialEq)]
pub enum Decision {
Permit,
Deny,
NotApplicable,
Indeterminate(String),
}
/// çç¥å®ä¹
#[derive(Debug, Clone)]
pub struct Policy {
pub id: String,
pub target: PolicyTarget,
pub rules: Vec<Rule>,
pub combining_algorithm: CombiningAlgorithm,
}
/// çç¥ç®æ ï¼å¹é
æ¡ä»¶ï¼
#[)]
pub struct PolicyTarget {
pubderive(Debug, Clone subjects: Vec<Vec<String>>, // è§è²ç»å
pub resources: Vec<String>,
pub actions: Vec<String>,
}
/// 访é®è§å
#[derive(Debug, Clone)]
pub struct Rule {
pub id: String,
pub effect: RuleEffect,
pub condition: Option<Box<dyn Fn(&RequestContext) -> bool + Send>>,
}
#[derive(Debug, Clone, Copy)]
pub enum RuleEffect {
Permit,
Deny,
}
/// çç¥ç»åç®æ³
#[derive(Debug, Clone, Copy)]
pub enum CombiningAlgorithm {
DenyOverrides, // Deny ä¼å
PermitOverrides, // Permit ä¼å
FirstApplicable, // é¦ä¸ªéç¨
OnlyOneApplicable, // ä»
ä¸ä¸ªéç¨
}
/// çç¥è¯ä¼°å¨
pub struct PolicyEvaluator {
policies: Vec<Policy>,
}
impl PolicyEvaluator {
pub fn new(policies: Vec<Policy>) -> Self {
Self { policies }
}
/// è¯ä¼°è¯·æ±
pub fn evaluate(&self, context: &RequestContext) -> Decision {
let mut applicable_policies: Vec<&Policy> = self.policies
.iter()
.filter(|p| self.is_target_matched(p, context))
.collect();
if applicable_policies.is_empty() {
return Decision::NotApplicable;
}
// æ ¹æ®ç»åç®æ³è®¡ç®æç»å³ç
match applicable_policies.first().map(|p| p.combining_algorithm).unwrap_or(CombiningAlgorithm::FirstApplicable) {
CombiningAlgorithm::DenyOverrides => self.deny_overrides(&applicable_policies, context),
CombiningAlgorithm::PermitOverrides => self.permit_overrides(&applicable_policies, context),
CombiningAlgorithm::FirstApplicable => self.first_applicable(&applicable_policies, context),
CombiningAlgorithm::OnlyOneApplicable => {
if applicable_policies.len() == 1 {
self.evaluate_policy(applicable_policies[0], context)
} else {
Decision::Indeterminate("Multiple applicable policies".to_string())
}
}
}
}
fn is_target_matched(&self, policy: &Policy, context: &RequestContext) -> bool {
// æ£æ¥ Subjects
let subject_matches = policy.target.subjects.is_empty() ||
policy.target.subjects.iter().any(|roles| {
roles.iter().all(|r| context.subject.roles.contains(r))
});
// æ£æ¥ Resources
let resource_matches = policy.target.resources.is_empty() ||
policy.target.resources.contains(&context.resource.r#type);
// æ£æ¥ Actions
let action_matches = policy.target.actions.is_empty() ||
policy.target.actions.contains(&context.action);
subject_matches && resource_matches && action_matches
}
fn deny_overrides(&self, policies: &[&Policy], context: &RequestContext) -> Decision {
let mut has_error = false;
let mut error_msg = String::new();
for policy in policies {
match self.evaluate_policy(policy, context) {
Decision::Deny => return Decision::Deny,
Decision::Indeterminate(msg) => {
has_error = true;
error_msg = msg;
}
_ => {}
}
}
if has_error {
Decision::Indeterminate(error_msg)
} else {
Decision::Permit
}
}
fn permit_overrides(&self, policies: &[&Policy], context: &RequestContext) -> Decision {
let mut has_error = false;
let mut error_msg = String::new();
for policy in policies {
match self.evaluate_policy(policy, context) {
Decision::Permit => return Decision::Permit,
Decision::Indeterminate(msg) => {
has_error = true;
error_msg = msg;
}
_ => {}
}
}
if has_error {
Decision::Indeterminate(error_msg)
} else {
Decision::Deny
}
}
fn first_applicable(&self, policies: &[&Policy], context: &RequestContext) -> Decision {
for policy in policies {
let decision = self.evaluate_policy(policy, context);
if decision != Decision::NotApplicable {
return decision;
}
}
Decision::Deny
}
fn evaluate_policy(&self, policy: &Policy, context: &RequestContext) -> Decision {
for rule in &policy.rules {
if let Some(ref condition) = rule.condition {
if !condition(context) {
continue;
}
}
return match rule.effect {
RuleEffect::Permit => Decision::Permit,
RuleEffect::Deny => Decision::Deny,
};
}
Decision::NotApplicable
}
}
2. RBAC æéæ£æ¥
//! RBAC æéæ£æ¥
use std::collections::HashMap;
/// RBAC é
ç½®
#[derive(Debug, Clone)]
pub struct RbacConfig {
/// è§è²å±çº§
pub role_hierarchy: HashMap<String, Vec<String>>,
/// è§è²æéæ å°
pub role_permissions: HashMap<String, Vec<String>>,
/// æéå®ä¹
pub permissions: HashMap<String, PermissionDef>,
}
/// æéå®ä¹
#[derive(Debug, Clone)]
pub struct PermissionDef {
pub resource: String,
pub actions: Vec<String>,
}
/// RBAC æ£æ¥å¨
pub struct RbacChecker {
config: RbacConfig,
}
impl RbacChecker {
pub fn new(config: RbacConfig) -> Self {
Self { config }
}
/// æ£æ¥ç¨æ·æ¯å¦ææé
pub fn check_permission(
&self,
user_roles: &[String],
resource: &str,
action: &str,
) -> bool {
// è·åææç»§æ¿çè§è²
let all_roles = self.expand_roles(user_roles);
// æ£æ¥æ¯å¦ææé
for role in &all_roles {
if let Some(perms) = self.config.role_permissions.get(role) {
for perm_id in perms {
if let Some(perm) = self.config.permissions.get(perm_id) {
if perm.resource == resource && perm.actions.contains(&action) {
return true;
}
}
}
}
}
false
}
/// å±å¼è§è²å±çº§
fn expand_roles(&self, roles: &[String]) -> Vec<String> {
let mut expanded = Vec::new();
let mut visited = std::collections::HashSet::new();
let mut queue = Vec::new();
for role in roles {
if !visited.contains(role) {
queue.push(role.clone());
visited.insert(role.clone());
}
}
while let Some(role) = queue.pop() {
expanded.push(role.clone());
if let Some(parents) = self.config.role_hierarchy.get(&role) {
for parent in parents {
if !visited.contains(parent) {
visited.insert(parent.clone());
queue.push(parent.clone());
}
}
}
}
expanded
}
/// è·åç¨æ·çæææé
pub fn get_user_permissions(&self, user_roles: &[String]) -> Vec<String> {
let all_roles = self.expand_roles(user_roles);
let mut permissions = std::collections::HashSet::new();
for role in &all_roles {
if let Some(role_perms) = self.config.role_permissions.get(role) {
for perm in role_perms {
permissions.insert(perm.clone());
}
}
}
permissions.into_iter().collect()
}
}
3. çç¥ç¼å
//! çç¥ç¼å
use crate::{Policy, PolicyEvaluator};
use std::sync::Arc;
use tokio::sync::RwLock;
use std::time::{Duration, Instant};
/// ç¼åé
ç½®
#[derive(Debug, Clone)]
pub struct PolicyCacheConfig {
pub ttl: Duration,
pub max_size: usize,
}
/// ç¼åæ¡ç®
struct CacheEntry {
policy: Policy,
inserted_at: Instant,
}
/// çç¥ç¼å
pub struct PolicyCache {
config: PolicyCacheConfig,
cache: Arc<RwLock<HashMap<String, CacheEntry>>>,
}
impl PolicyCache {
pub fn new(config: PolicyCacheConfig) -> Self {
Self {
config,
cache: Arc::new(RwLock::new(HashMap::new())),
}
}
/// è·åçç¥
pub async fn get(&self, policy_id: &str) -> Option<Policy> {
let cache = self.cache.read().await;
cache.get(policy_id).map(|entry| entry.policy.clone())
}
/// åå¨çç¥
pub async fn set(&self, policy: Policy) {
let mut cache = self.cache.write().await;
// æ¸
çè¿ææ¡ç®
let now = Instant::now();
cache.retain(|_, v| now.duration_since(v.inserted_at) < self.config.ttl);
// æ¸
çè¶
åºå¤§å°çæ¡ç®
if cache.len() >= self.config.max_size {
let to_remove = cache.len() - self.config.max_size + 1;
let keys: Vec<String> = cache.keys().take(to_remove).cloned().collect();
for key in keys {
cache.remove(&key);
}
}
cache.insert(policy.id.clone(), CacheEntry {
policy,
inserted_at: Instant::now(),
});
}
/// 失æçç¥
pub async fn invalidate(&self, policy_id: &str) {
let mut cache = self.cache.write().await;
cache.remove(policy_id);
}
/// æ¸
çææ
pub async fn clear(&self) {
let mut cache = self.cache.write().await;
cache.clear();
}
}
æä½³å®è·µ
1. çç¥å®ä¹ DSL
//! çç¥æå»ºå¨
use crate::{Policy, PolicyTarget, Rule, RuleEffect, CombiningAlgorithm};
/// çç¥æå»ºå¨
pub struct PolicyBuilder {
policy: Policy,
}
impl PolicyBuilder {
pub fn new(id: &str) -> Self {
Self {
policy: Policy {
id: id.to_string(),
target: PolicyTarget {
subjects: Vec::new(),
resources: Vec::new(),
actions: Vec::new(),
},
rules: Vec::new(),
combining_algorithm: CombiningAlgorithm::DenyOverrides,
},
}
}
pub fn with_subject_roles(mut self, roles: &[&str]) -> Self {
self.policy.target.subjects = vec![roles.iter().map(|s| s.to_string()).collect()];
self
}
pub fn with_resource(mut self, resource: &str) -> Self {
self.policy.target.resources = vec![resource.to_string()];
self
}
pub fn with_action(mut self, action: &str) -> Self {
self.policy.target.actions = vec![action.to_string()];
self
}
pub fn add_rule(
mut self,
id: &str,
effect: RuleEffect,
condition: impl Fn(&crate::RequestContext) -> bool + Send + 'static,
) -> Self {
self.policy.rules.push(Rule {
id: id.to_string(),
effect,
condition: Some(Box::new(condition)),
});
self
}
pub fn with_combining_algorithm(mut self, algo: CombiningAlgorithm) -> Self {
self.policy.combining_algorithm = algo;
self
}
pub fn build(self) -> Policy {
self.policy
}
}
/// 使ç¨ç¤ºä¾
fn example_policy() -> Policy {
PolicyBuilder::new("read-policy")
.with_subject_roles(&["user", "admin"])
.with_resource("document")
.with_action("read")
.add_rule("own-document", RuleEffect::Permit, |ctx| {
// èªå·±åå»ºçææ¡£å¯ä»¥è¯»å
ctx.resource.attributes.get("owner") == Some(&ctx.subject.id)
})
.add_rule("public-document", RuleEffect::Permit, |ctx| {
// å
¬å¼ææ¡£å¯ä»¥è¯»å
ctx.resource.attributes.get("visibility") == Some(&"public".to_string())
})
.with_combining_algorithm(CombiningAlgorithm::DenyOverrides)
.build()
}
常è§é®é¢
| é®é¢ | åå | è§£å³æ¹æ¡ |
|---|---|---|
| å³çä¸ä¸è´ | ç»åç®æ³éæ©ä¸å½ | æ ¹æ®ä¸å¡éæ©åéçç®æ³ |
| æ§è½å·® | çç¥è¿å¤ | 使ç¨ç¼ååç´¢å¼ |
| æéç»è¿ | è§å顺åºé®é¢ | DenyOverrides ä¼å |
å ³èæè½
rust-auth– è®¤è¯æærust-web– Web éærust-cache– çç¥ç¼årust-performance– æ§è½ä¼å