Crates.io | actix-cloud |
lib.rs | actix-cloud |
version | 0.4.5 |
source | src |
created_at | 2024-08-13 17:39:45.998344 |
updated_at | 2024-11-04 12:45:46.685708 |
description | Actix Cloud is an all-in-one web framework based on Actix Web. |
homepage | |
repository | https://github.com/MXWXZ/actix-cloud |
max_upload_size | |
id | 1336307 |
size | 114,986 |
Actix Cloud is an all-in-one web framework based on Actix Web.
Actix Cloud is highly configurable. You can only enable needed features, implement your own feature backend or even use other libraries.
You can refer to Hello world example for basic usage.
Since application configuration can be quite dynamic, you need to build on your own. Here are some useful middlewares:
App::new()
.wrap(middleware::Compress::default()) // compress page
.wrap(SecurityHeader::default().build()) // default security header
.wrap(SessionMiddleware::builder(memorydb.clone(), Key::generate()).build()) // session
...
.app_data(state_cloned.clone())
We use tracing as our logger library. It is thread safe. You can use it everywhere.
Start logger:
LoggerBuilder::new().level(Level::DEBUG).start() // colorful output
LoggerBuilder::new().json().start() // json output
You can also customize the logger with filter
, transformer
, etc.
Reinit logger (e.g., in plugins), or manually send logs:
logger.init(LoggerBuilder::new());
logger.sender().send(...);
Reserved field:
_time
: timestamp in microseconds, override the log timestamp.We use rust-i18n-support
from rust-i18n as our i18n core.
Load locale:
let locale = Locale::new(String::from("en-US")).add_locale(i18n!("locale"));
Translate:
t!(locale, "hello.world")
t!(locale, "hello.name", name = "MEME")
See examples for more usage.
Middleware to add security headers:
app.wrap(SecurityHeader::default().build())
Default header:
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Cross-Origin-Opener-Policy: same-origin
Content-Security-Policy: default-src 'none'; script-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-ancestors 'none'
Enable HSTS when using HTTPS:
security_header.set_default_hsts();
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Actix Cloud has a default memory database backend used for sessions. You can also use your own backend if you implement actix_cloud::memorydb::MemoryDB
.
Note: the default backend does not have memory limitation, DDoS is possible if gateway rate limiting is not implemented
DefaultBackend::new()
Redis can be used as another backend for memory database.
RedisBackend::new("redis://user:pass@127.0.0.1:6379/0").await.unwrap(),
Authentication is quite simple, you only need to implement a checker.
Checker is used to check the permission, the server will return 403 if the return value is false:
struct AuthChecker {
need_admin: bool,
}
impl AuthChecker {
fn new(need_admin: bool) -> Self {
Self { need_admin }
}
}
#[async_trait(?Send)]
impl Checker for AuthChecker {
async fn check(&self, req: &mut ServiceRequest) -> Result<bool> {
let qs = QString::from(req.query_string());
let is_admin = if qs.get("admin").is_some_and(|x| x == "1") {
true
} else {
false
};
if (is_admin && self.need_admin) || !self.need_admin {
Ok(true)
} else {
Ok(false)
}
}
}
Then build the Router
and configure in the App using build_router
:
app.service(scope("/api").configure(build_router(...)))
Most features and usages are based on actix-session. Except for these:
actix-cloud::error::Error
._ttl
in the session to override the TTL of the session._id
in the session for reverse search.
{_id}_{session_key}
. You can use keys
function to find all session key binding to a specific id.app.wrap(SessionMiddleware::builder(memorydb.clone(), Key::generate()).build())
config-rs is the underlying library.
Supported features:
Provide per-request extension.
Built-in middleware:
i18n
feature is enabled, language is identified through the callback, or locale.default
in GlobalState
.Enable built-in middleware:
app.wrap(request::Middleware::new())
Usage:
async fn handler(req: HttpRequest) -> impl Responder {
let ext = req.extensions();
let ext = ext.get::<Arc<actix_cloud::request::Extension>>().unwrap();
...
}
async fn handler(ext: ReqData<Arc<actix_cloud::request::Extension>>) -> impl Responder {
...
}
Provide useful response type.
If i18n
feature is enabled, response message will be translated automatically.
If response-json
feature is enabled, response message will be converted to JSON automatically.
build.rs
to generate source files.include!
to include generated files.See examples for detailed usage.
Add trace ID for each request based on tracing-actix-web.
app.wrap(request::Middleware::new())
.wrap(TracingLogger::default()) // This should be after request::Middleware
If you enable request
feature, make sure it is before TracingLogger
since the trace_id
field is based on it.
Provide useful macros for seaorm.
#[derive(...)]
#[sea_orm(...)]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]
pub id: Uuid,
pub created_at: i64,
pub updated_at: i64,
}
#[entity_id(Uuid::new_v4())] // generate new for `id` field.
#[entity_timestamp] // automatically handle `created_at` and `updated_at` field.
impl ActiveModel {}
#[entity_behavior] // enable `entity_id` and `entity_timestamp`.
impl ActiveModelBehavior for ActiveModel {}
We use double submit to protect against CSRF attacks.
You can use memorydb
to store and check CSRF tokens.
By default, CSRF checker is applied to:
CSRFType
is Disabled
.CSRFType
is ForceHeader
or ForceParam
.Generally, Param
and ForceParam
type should only be used for websocket.
build_router(
route,
csrf::Middleware::new(
String::from("CSRF_TOKEN"), // csrf cookie
String::from("X-CSRF-Token"), // csrf header/param
|req, token| Box::pin(async { Ok(true) }) // csrf checker
),
);
This project is licensed under the MIT license.