授权控制 #

角色管理 #

定义角色 #

rust
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Role {
    Admin,
    User,
    Guest,
}

impl Role {
    pub fn has_permission(&self, permission: &Permission) -> bool {
        match self {
            Role::Admin => true,
            Role::User => matches!(
                permission,
                Permission::ReadOwn | Permission::WriteOwn
            ),
            Role::Guest => matches!(permission, Permission::ReadOwn),
        }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Permission {
    ReadOwn,
    WriteOwn,
    ReadAll,
    WriteAll,
    Delete,
}

用户结构 #

rust
#[derive(Debug, Clone)]
pub struct AuthUser {
    pub id: String,
    pub role: Role,
}

impl AuthUser {
    pub fn has_permission(&self, permission: &Permission) -> bool {
        self.role.has_permission(permission)
    }
}

授权中间件 #

rust
use actix_web::{dev::Payload, Error, FromRequest, HttpRequest};
use futures::future::{ready, Ready};

pub struct AuthorizedUser {
    pub user: AuthUser,
}

impl FromRequest for AuthorizedUser {
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let user = req.extensions().get::<AuthUser>().cloned();
        
        match user {
            Some(user) => ready(Ok(AuthorizedUser { user })),
            None => ready(Err(actix_web::error::ErrorUnauthorized("Unauthorized"))),
        }
    }
}

权限检查 #

手动检查 #

rust
#[actix_web::delete("/users/{id}")]
async fn delete_user(
    path: web::Path<String>,
    auth: AuthorizedUser,
) -> impl Responder {
    if !auth.user.has_permission(&Permission::Delete) {
        return HttpResponse::Forbidden().json(serde_json::json!({
            "error": "Permission denied"
        }));
    }
    
    HttpResponse::NoContent().finish()
}

自定义提取器 #

rust
pub struct AdminUser(pub AuthUser);

impl FromRequest for AdminUser {
    type Error = Error;
    type Future = Ready<Result<Self, Self::Error>>;

    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        let user = req.extensions().get::<AuthUser>().cloned();
        
        match user {
            Some(user) if user.role == Role::Admin => ready(Ok(AdminUser(user))),
            Some(_) => ready(Err(actix_web::error::ErrorForbidden("Admin access required"))),
            None => ready(Err(actix_web::error::ErrorUnauthorized("Unauthorized"))),
        }
    }
}

#[actix_web::get("/admin/users")]
async fn list_all_users(_admin: AdminUser) -> impl Responder {
    HttpResponse::Ok().json(serde_json::json!({ "users": [] }))
}

下一步 #

继续学习 CORS 跨域,了解跨域资源共享!

最后更新:2026-03-29