@roles_allowed
Java EE-style role-based security. Functionally equivalent to #[secured].
Syntax
#[roles_allowed("ROLE")] // Single role
#[roles_allowed("ROLE1", "ROLE2")] // Multiple roles (OR logic)
Usage
use actix_web::{get, HttpResponse, Responder};
use actix_security::roles_allowed;
use actix_security::http::security::AuthenticatedUser;
// Single role
#[roles_allowed("ADMIN")]
#[get("/admin")]
async fn admin_panel(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Admin Panel")
}
// Multiple roles
#[roles_allowed("ADMIN", "MANAGER")]
#[get("/management")]
async fn management(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Management")
}
Java EE Equivalent
This macro follows the Java EE @RolesAllowed annotation:
Java EE:
@RolesAllowed("ADMIN")
@GET
@Path("/admin")
public String admin() {
return "admin";
}
@RolesAllowed({"ADMIN", "MANAGER"})
@GET
@Path("/management")
public String management() {
return "management";
}
Actix Security:
#[roles_allowed("ADMIN")]
#[get("/admin")]
async fn admin(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("admin")
}
#[roles_allowed("ADMIN", "MANAGER")]
#[get("/management")]
async fn management(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("management")
}
Comparison with @secured
#[roles_allowed] and #[secured] are functionally identical. Choose based on your preferred naming convention:
| If you're coming from... | Use |
|---|---|
| Spring Security | #[secured] |
| Java EE / Jakarta EE | #[roles_allowed] |
// These are equivalent:
#[roles_allowed("ADMIN")]
#[get("/admin")]
async fn admin_v1(user: AuthenticatedUser) -> impl Responder { /* ... */ }
#[secured("ADMIN")]
#[get("/admin")]
async fn admin_v2(user: AuthenticatedUser) -> impl Responder { /* ... */ }
OR Logic
Like #[secured], multiple roles use OR logic:
#[roles_allowed("ADMIN", "MANAGER", "SUPERVISOR")]
#[get("/reports")]
async fn reports(user: AuthenticatedUser) -> impl Responder {
// Access granted if user has ADMIN OR MANAGER OR SUPERVISOR
HttpResponse::Ok().body("Reports")
}
For AND logic, use #[pre_authorize]:
#[pre_authorize("hasRole('ADMIN') AND hasRole('AUDITOR')")]
#[get("/audit")]
async fn audit(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Audit")
}
Examples
Admin Dashboard
#[roles_allowed("ADMIN")]
#[get("/admin/dashboard")]
async fn admin_dashboard(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body(format!("Welcome, Admin {}!", user.get_username()))
}
Multi-Tier Access
// Executive + Management access
#[roles_allowed("EXECUTIVE", "MANAGER")]
#[get("/reports/financial")]
async fn financial_reports(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Financial Reports")
}
// All staff access
#[roles_allowed("EXECUTIVE", "MANAGER", "EMPLOYEE")]
#[get("/reports/general")]
async fn general_reports(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("General Reports")
}
Service Account
#[roles_allowed("SERVICE", "ADMIN")]
#[post("/internal/sync")]
async fn internal_sync(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Synchronized")
}
How It Works
#[roles_allowed] delegates to #[secured] internally:
// Input
#[roles_allowed("ADMIN", "MANAGER")]
#[get("/management")]
async fn management(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Management")
}
// Effectively same as
#[secured("ADMIN", "MANAGER")]
#[get("/management")]
async fn management(user: AuthenticatedUser) -> impl Responder {
HttpResponse::Ok().body("Management")
}
// Which expands to (simplified)
#[get("/management")]
async fn management(user: AuthenticatedUser) -> Result<impl Responder, AuthError> {
if !user.has_any_role(&["ADMIN".to_string(), "MANAGER".to_string()]) {
return Err(AuthError::Forbidden);
}
Ok(HttpResponse::Ok().body("Management"))
}
When to Use
Use #[roles_allowed] when:
- You prefer Java EE naming conventions
- You're porting code from Java EE
- Your team is familiar with
@RolesAllowed
Use #[secured] instead when:
- You prefer Spring Security naming conventions
- Your team is familiar with
@Secured
Use #[pre_authorize] instead when:
- You need authority checks (not just roles)
- You need complex AND/OR/NOT logic
- You need expression-based security