larust_auth/authorize.rs
1use axum::http::StatusCode;
2use larust_core::AppError;
3
4/// Converts a boolean authorization check into a 403 on failure (Laravel's
5/// `$this->authorize(...)` controller helper). Not a `Gate`-style runtime
6/// registry - write the actual check as a plain typed method on your own
7/// model (`impl Post { pub fn can_update(&self, user: &User) -> bool {
8/// self.user_id == user.id } }`) and convert it at the call site:
9/// `authorize(post.can_update(&user))?;`. A typo in an ability name this
10/// way is a compile error, not a silently-always-false runtime lookup.
11///
12/// For the common CRUD-shaped case (view/create/update/delete on a model),
13/// prefer [`crate::Policy`] instead - it gives every model the same
14/// ability names and a matching `authorize_*` sugar method
15/// (`post.authorize_update(&user)?`) built on this same function. This
16/// helper remains the right tool for one-off, non-CRUD-shaped checks.
17pub fn authorize(allowed: bool) -> Result<(), AppError> {
18 if allowed {
19 Ok(())
20 } else {
21 Err(AppError::Http {
22 status: StatusCode::FORBIDDEN,
23 message: "This action is unauthorized.".to_string(),
24 })
25 }
26}
27
28#[cfg(test)]
29mod tests {
30 use super::*;
31
32 #[test]
33 fn allows_when_true() {
34 assert!(authorize(true).is_ok());
35 }
36
37 #[test]
38 fn rejects_with_403_when_false() {
39 let err = authorize(false).unwrap_err();
40 assert!(matches!(
41 err,
42 AppError::Http {
43 status: StatusCode::FORBIDDEN,
44 ..
45 }
46 ));
47 }
48}