CODESAMPLE

Policy - Rust

Share on:

The Policy pattern allows you to decouple the logic that determines if an operation is allowed from the operation itself. It achieves this by defining a “policy” – a trait or interface – that encapsulates the authorization rules. Different policies can be swapped in at runtime to change the behavior without modifying the core operation.

This Rust implementation defines a Policy trait with a check() method. A concrete AdminPolicy and ReadOnlyPolicy implement this trait, representing different access levels. The perform_action function takes a Policy as input, allowing it to execute the action only if the policy permits it. This is idiomatic Rust due to its use of traits for polymorphism and ownership/borrowing to ensure safe access control. The use of a trait object allows for flexible policy selection at runtime.

// Define the Policy trait
trait Policy {
    fn check(&self, user_role: &str) -> bool;
}

// Concrete Policy: AdminPolicy
struct AdminPolicy;

impl Policy for AdminPolicy {
    fn check(&self, user_role: &str) -> bool {
        user_role == "admin"
    }
}

// Concrete Policy: ReadOnlyPolicy
struct ReadOnlyPolicy;

impl Policy for ReadOnlyPolicy {
    fn check(&self, user_role: &str) -> bool {
        user_role == "admin" || user_role == "user"
    }
}

// The operation that uses the policy
fn perform_action(policy: &dyn Policy, user_role: &str) {
    if policy.check(user_role) {
        println!("Action performed successfully by user with role: {}", user_role);
    } else {
        println!("Permission denied for user with role: {}", user_role);
    }
}

fn main() {
    let admin_policy = AdminPolicy;
    let read_only_policy = ReadOnlyPolicy;

    perform_action(&admin_policy, "admin"); // Action performed
    perform_action(&admin_policy, "user");  // Permission denied
    perform_action(&read_only_policy, "user"); // Action performed
    perform_action(&read_only_policy, "guest"); // Permission denied
}