AuthorizationDecision

Enum AuthorizationDecision 

Source
pub enum AuthorizationDecision<AllowedReason = (), ForbiddenReason = ()> {
    Allowed {
        reason: AllowedReason,
    },
    Forbidden {
        reason: ForbiddenReason,
    },
}
Expand description

§AuthorizationDecision

Output type for authorizers.

It is an enum designating whether an action is permitted (Allowed) or denied (Forbidden). Both variants of the enum may carry a user-defined and accessible “reason” payload for logic branching, API error messages, metrics and analytics, etc.

Both reason types default to unit, and you can have both typed, just one, or neither. Often forbidden reasons are used heavily, but allowed reasons are not unless there’s particular compliance or audit/logging required for sensitive resources.

They are simple enums with no references to the inputs of the authorizer or anything like this, so feel free to store and pass them around if needed, pass them down from middleware to core logic, create them for unit tests, etc.

§Constructors

MethodDescription
allowed() / forbidden()Create a decision without a reason.
allowed_with(reason) / forbidden_with(reason)Create a decision with an attached reason.

§Utilities

Predicates: is_allowed(), is_forbidden() Result conversion: into_result()Result<AllowedReason, ForbiddenReason> ok_or(err) / ok_or_else(f) → convert to Result<(), E> Assertions / unwraps: expect_allowed(msg), expect_forbidden(msg), unwrap_allowed(), unwrap_forbidden() Inspection: inspect_allowed(|r| …), inspect_forbidden(|r| …) (executes the closure for side effects, returns self unchanged)

§Examples

§1 – Minimal check without reasons

use traitgate::AuthorizationDecision;

let dec: AuthorizationDecision<(), ()> = AuthorizationDecision::allowed();
assert!(dec.is_allowed());

§2 – Custom deny reason

use traitgate::AuthorizationDecision;

#[derive(Debug, PartialEq)]
enum PostDeny { NotAuthor, RateLimited }

let denied = AuthorizationDecision::<(), PostDeny>::forbidden_with(PostDeny::RateLimited);
assert_eq!(denied.into_result(), Err(PostDeny::RateLimited));

§3 – Logging an allow reason

use traitgate::AuthorizationDecision;

let decision = AuthorizationDecision::<&str, ()>::allowed_with("scope=admin");
decision
    .inspect_allowed(|r| println!("granted via {}", r))
    .expect_allowed("expected to be allowed");

Variants§

§

Allowed

The authorization is allowed, with an optional reason.

Fields

§reason: AllowedReason
§

Forbidden

The authorization is forbidden, with an optional reason.

Fields

§reason: ForbiddenReason

Implementations§

Source§

impl<F> AuthorizationDecision<(), F>

Source

pub fn allowed() -> Self

Create an Allowed decision when you don’t need a reason.

use traitgate::prelude::*;
let ok = AuthorizationDecision::<(),()>::allowed();
assert!(ok.is_allowed());
Source§

impl<A> AuthorizationDecision<A, ()>

Source

pub fn forbidden() -> Self

Create a Forbidden decision when you don’t need a reason.

use traitgate::prelude::*;
let no = AuthorizationDecision::<(),()>::forbidden();
assert!(no.is_forbidden());
Source§

impl<A, F> AuthorizationDecision<A, F>

Source

pub fn allowed_with(reason: A) -> Self

Create Allowed { reason } with your custom allow-reason.

use traitgate::prelude::*;
struct NewPostAllowed { is_author: bool }
AuthorizationDecision::<NewPostAllowed, ()>::allowed_with(NewPostAllowed { is_author: true });
Source

pub fn forbidden_with(reason: F) -> Self

Create Forbidden { reason } with your custom deny-reason.

use traitgate::prelude::*;
enum OrderModifyForbiddenReason {
  OrderIsHaunted,
  NotOwner
}
let dec = AuthorizationDecision::<(), OrderModifyForbiddenReason>::forbidden_with(OrderModifyForbiddenReason::NotOwner);
Source

pub fn is_allowed(&self) -> bool

Return true if the decision is Allowed

Source

pub fn is_forbidden(&self) -> bool

Return true if the decision is Forbidden

Source

pub fn ok_or<E>(self, err: E) -> Result<(), E>

Convert into Result<(), E>, using err when forbidden.

use traitgate::prelude::*;
let dec = AuthorizationDecision::<(),()>::allowed();
let res: Result<(), &str> = dec.ok_or("access denied");
Source

pub fn ok_or_else<E, G>(self, err_fn: G) -> Result<(), E>
where G: FnOnce(F) -> E,

Like ok_or, but builds the error from the forbidden reason.

Source

pub fn into_result(self) -> Result<A, F>

Convert into Result<AllowedReason, ForbiddenReason>.

Source

pub fn expect_allowed(self, msg: &str) -> A

Panic with msg if forbidden; otherwise return the allowed reason.

// panics if decision is forbidden
use traitgate::prelude::*;
let dec = AuthorizationDecision::<(),()>::allowed();
let reason = dec.expect_allowed("must be allowed");
Source

pub fn expect_forbidden(self, msg: &str) -> F

Panic with msg if allowed; otherwise return the forbidden reason.

// panics if decision is forbidden
use traitgate::prelude::*;
let dec = AuthorizationDecision::<(),()>::forbidden();
let reason = dec.expect_forbidden("must be forbidden");
Source

pub fn unwrap_forbidden(self) -> F

Panic if allowed; otherwise return the forbidden reason.

// panics if decision is allowed
use traitgate::prelude::*;
let dec = AuthorizationDecision::<(),()>::forbidden();
let reason = dec.unwrap_forbidden();
Source

pub fn unwrap_allowed(self) -> A

Panic if forbidden; otherwise return the allowed reason.

// panics if decision is forbidden
use traitgate::prelude::*;
let dec = AuthorizationDecision::<(),()>::allowed();
let reason = dec.unwrap_allowed();
Source

pub fn inspect_forbidden<G: FnOnce(&F)>(self, inspect_fn: G) -> Self

If this decision is Forbidden, runs inspect_fn(&reason)as a side‐effect, then returns the original decision unchanged.

§Example
let dec = AuthorizationDecision::<(), &str>::forbidden_with("not owner");
dec.inspect_forbidden(|reason| println!("Denied because {}", reason));
Source

pub fn inspect_allowed<G: FnOnce(&A)>(self, inspect_fn: G) -> Self

If this decision is Forbidden, runs inspect_fn(&reason) for a side‐effect, then returns the original decision unchanged.

§Example
let dec = AuthorizationDecision::<&str,()>::allowed_with("admin");
dec.inspect_allowed(|reason| println!("Granted because {}", reason));

Trait Implementations§

Source§

impl<AllowedReason: Clone, ForbiddenReason: Clone> Clone for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

fn clone(&self) -> AuthorizationDecision<AllowedReason, ForbiddenReason>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<AllowedReason: Debug, ForbiddenReason: Debug> Debug for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<A, F> Display for AuthorizationDecision<A, F>
where A: Display, F: Display,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<AllowedReason: Hash, ForbiddenReason: Hash> Hash for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl<AllowedReason: Ord, ForbiddenReason: Ord> Ord for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

fn cmp( &self, other: &AuthorizationDecision<AllowedReason, ForbiddenReason>, ) -> Ordering

This method returns an Ordering between self and other. Read more
1.21.0 · Source§

fn max(self, other: Self) -> Self
where Self: Sized,

Compares and returns the maximum of two values. Read more
1.21.0 · Source§

fn min(self, other: Self) -> Self
where Self: Sized,

Compares and returns the minimum of two values. Read more
1.50.0 · Source§

fn clamp(self, min: Self, max: Self) -> Self
where Self: Sized,

Restrict a value to a certain interval. Read more
Source§

impl<AllowedReason: PartialEq, ForbiddenReason: PartialEq> PartialEq for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

fn eq( &self, other: &AuthorizationDecision<AllowedReason, ForbiddenReason>, ) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<AllowedReason: PartialOrd, ForbiddenReason: PartialOrd> PartialOrd for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

fn partial_cmp( &self, other: &AuthorizationDecision<AllowedReason, ForbiddenReason>, ) -> Option<Ordering>

This method returns an ordering between self and other values if one exists. Read more
1.0.0 · Source§

fn lt(&self, other: &Rhs) -> bool

Tests less than (for self and other) and is used by the < operator. Read more
1.0.0 · Source§

fn le(&self, other: &Rhs) -> bool

Tests less than or equal to (for self and other) and is used by the <= operator. Read more
1.0.0 · Source§

fn gt(&self, other: &Rhs) -> bool

Tests greater than (for self and other) and is used by the > operator. Read more
1.0.0 · Source§

fn ge(&self, other: &Rhs) -> bool

Tests greater than or equal to (for self and other) and is used by the >= operator. Read more
Source§

impl<AllowedReason: Copy, ForbiddenReason: Copy> Copy for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

impl<AllowedReason: Eq, ForbiddenReason: Eq> Eq for AuthorizationDecision<AllowedReason, ForbiddenReason>

Source§

impl<AllowedReason, ForbiddenReason> StructuralPartialEq for AuthorizationDecision<AllowedReason, ForbiddenReason>

Auto Trait Implementations§

§

impl<AllowedReason, ForbiddenReason> Freeze for AuthorizationDecision<AllowedReason, ForbiddenReason>
where AllowedReason: Freeze, ForbiddenReason: Freeze,

§

impl<AllowedReason, ForbiddenReason> RefUnwindSafe for AuthorizationDecision<AllowedReason, ForbiddenReason>
where AllowedReason: RefUnwindSafe, ForbiddenReason: RefUnwindSafe,

§

impl<AllowedReason, ForbiddenReason> Send for AuthorizationDecision<AllowedReason, ForbiddenReason>
where AllowedReason: Send, ForbiddenReason: Send,

§

impl<AllowedReason, ForbiddenReason> Sync for AuthorizationDecision<AllowedReason, ForbiddenReason>
where AllowedReason: Sync, ForbiddenReason: Sync,

§

impl<AllowedReason, ForbiddenReason> Unpin for AuthorizationDecision<AllowedReason, ForbiddenReason>
where AllowedReason: Unpin, ForbiddenReason: Unpin,

§

impl<AllowedReason, ForbiddenReason> UnwindSafe for AuthorizationDecision<AllowedReason, ForbiddenReason>
where AllowedReason: UnwindSafe, ForbiddenReason: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.