backend/config/auth/
user_info.rs1use actix_http::{HttpMessage, StatusCode};
4use actix_utils::future::{ready, Ready};
5use actix_web::FromRequest;
6use serde::Deserialize;
7use uuid::Uuid;
8
9use crate::error::ServiceError;
10
11use super::claims::Claims;
12
13#[derive(Debug, Clone, Deserialize)]
15pub struct UserInfo {
16 pub id: Uuid,
18 pub scopes: Vec<String>,
20 pub roles: Vec<Role>,
22}
23
24#[derive(Debug, Clone, Deserialize)]
26pub enum Role {
27 Member,
29 Testing,
31 Admin,
33}
34
35impl UserInfo {
36 #[must_use]
38 pub fn is_member(&self) -> bool {
39 self.roles.iter().any(|role| matches!(role, Role::Member))
40 }
41
42 #[must_use]
45 pub fn is_admin(&self) -> bool {
46 self.roles
47 .iter()
48 .any(|role| matches!(role, Role::Admin | Role::Testing))
49 }
50}
51
52impl Role {
53 #[must_use]
55 pub fn from_string(str: &str) -> Option<Self> {
56 match str {
57 "/Member" => Some(Self::Member),
58 "/Testing" => Some(Self::Testing),
59 "/Admin" => Some(Self::Admin),
60 _ => None,
61 }
62 }
63}
64
65impl From<Claims> for UserInfo {
68 fn from(value: Claims) -> Self {
69 let roles = value.groups.map_or_else(Vec::new, |groups| {
70 groups
71 .into_iter()
72 .filter_map(|s| Role::from_string(&s))
73 .collect::<Vec<_>>()
74 });
75
76 Self {
77 id: value.sub,
78 scopes: value.scope.split(' ').map(str::to_owned).collect(),
79 roles,
80 }
81 }
82}
83
84impl FromRequest for UserInfo {
85 type Future = Ready<Result<Self, Self::Error>>;
86 type Error = ServiceError;
87
88 fn from_request(
89 req: &actix_web::HttpRequest,
90 _payload: &mut actix_http::Payload,
91 ) -> Self::Future {
92 let extensions = req.extensions();
93 ready({
94 extensions.get::<Self>().map_or_else(
95 || {
96 Err(ServiceError::new(
97 StatusCode::INTERNAL_SERVER_ERROR,
98 &StatusCode::INTERNAL_SERVER_ERROR.to_string(),
99 ))
100 },
101 |user_info| Ok(user_info.clone()),
102 )
103 })
104 }
105}