NAC_Blockchain/nac_wallet_service/src/middleware.rs

165 lines
4.7 KiB
Rust

use actix_web::{
dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},
Error, HttpResponse,
};
use futures_util::future::{LocalBoxFuture, Ready, ready, ok};
use std::rc::Rc;
/// 请求日志中间件
pub struct RequestLogger;
impl<S, B> Transform<S, ServiceRequest> for RequestLogger
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = RequestLoggerMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(RequestLoggerMiddleware { service })
}
}
pub struct RequestLoggerMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for RequestLoggerMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let method = req.method().to_string();
let path = req.path().to_string();
let fut = self.service.call(req);
Box::pin(async move {
let res = fut.await?;
tracing::info!("{} {} -> {}", method, path, res.status());
Ok(res)
})
}
}
/// 安全响应头中间件
pub struct SecurityHeaders;
impl<S, B> Transform<S, ServiceRequest> for SecurityHeaders
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = SecurityHeadersMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(SecurityHeadersMiddleware { service })
}
}
pub struct SecurityHeadersMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for SecurityHeadersMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
let fut = self.service.call(req);
Box::pin(async move {
let mut res = fut.await?;
let headers = res.headers_mut();
headers.insert(
actix_web::http::header::HeaderName::from_static("x-content-type-options"),
actix_web::http::header::HeaderValue::from_static("nosniff"),
);
headers.insert(
actix_web::http::header::HeaderName::from_static("x-frame-options"),
actix_web::http::header::HeaderValue::from_static("DENY"),
);
Ok(res)
})
}
}
/// 管理员JWT认证中间件
pub struct AdminAuth;
impl<S, B> Transform<S, ServiceRequest> for AdminAuth
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = AdminAuthMiddleware<S>;
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
ok(AdminAuthMiddleware { service })
}
}
pub struct AdminAuthMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest> for AdminAuthMiddleware<S>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
S::Future: 'static,
B: 'static,
{
type Response = ServiceResponse<B>;
type Error = Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
// 检查Authorization头
let auth_header = req.headers()
.get("Authorization")
.and_then(|v| v.to_str().ok())
.and_then(|v| v.strip_prefix("Bearer "))
.map(|s| s.to_string());
if auth_header.is_none() {
let (req, _) = req.into_parts();
return Box::pin(async move {
Err(actix_web::error::ErrorUnauthorized("需要管理员令牌"))
});
}
let fut = self.service.call(req);
Box::pin(async move { fut.await })
}
}