问题描述
我如何实现特征?在运行货物构建时,我收到此错误。
我也注释掉了 type Request = ServiceRequest;
。这将如何影响代码?我在 Cargo.toml 中将 actix-service 更新为 2.0.0-beta.2,然后构建失败。
error[E0107]: missing generics for trait `actix_service::Service`
--> src/middleware.rs:57:8
|
57 | S: Service<Response = ServiceResponse<B>,Error = Error> + 'static,| ^^^^^^^ expected 1 type argument
|
note: trait defined here,with 1 type parameter: `Req`
--> /home/samarpan/.cargo/registry/src/github.com-1ecc6299db9ec823/actix-service-2.0.0-beta.5/src/lib.rs:85:11
|
85 | pub trait Service<Req> {
| ^^^^^^^ ---
help: use angle brackets to add missing type argument
|
57 | S: Service<Req><Response = ServiceResponse<B>,| ^^^^^
这是我的中间件.rs -
#![allow(clippy::type_complexity)]
use std::cell::RefCell;
use std::ops::{Deref,DerefMut};
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context,Poll};
use futures::future::{ok,Ready};
use futures::Future;
use actix_service::{Service,Transform};
use actix_web::{
dev::ServiceRequest,dev::ServiceResponse,Error,HttpMessage,HttpResponse,Result,};
use casbin::prelude::{TryIntoAdapter,TryIntoModel};
use casbin::{CachedEnforcer,CoreApi,Result as casbinResult};
#[cfg(feature = "runtime-tokio")]
use tokio::sync::RwLock;
#[cfg(feature = "runtime-async-std")]
use async_std::sync::RwLock;
#[derive(Clone)]
pub struct casbinVals {
pub subject: String,pub domain: Option<String>,}
#[derive(Clone)]
pub struct casbinService {
enforcer: Arc<RwLock<CachedEnforcer>>,}
impl casbinService {
pub async fn new<M: TryIntoModel,A: TryIntoAdapter>(m: M,a: A) -> casbinResult<Self> {
let enforcer: CachedEnforcer = CachedEnforcer::new(m,a).await?;
Ok(casbinService {
enforcer: Arc::new(RwLock::new(enforcer)),})
}
pub fn get_enforcer(&mut self) -> Arc<RwLock<CachedEnforcer>> {
self.enforcer.clone()
}
pub fn set_enforcer(e: Arc<RwLock<CachedEnforcer>>) -> casbinService {
casbinService { enforcer: e }
}
}
impl<S,B> Transform<S,B> for casbinService
where
S: Service<Response = ServiceResponse<B>,S::Future: 'static,B: 'static,{
//type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type InitError = ();
type Transform = casbinMiddleware<S>;
type Future = Ready<Result<Self::Transform,Self::InitError>>;
fn new_transform(&self,service: S) -> Self::Future {
ok(casbinMiddleware {
enforcer: self.enforcer.clone(),service: Rc::new(RefCell::new(service)),})
}
}
impl Deref for casbinService {
type Target = Arc<RwLock<CachedEnforcer>>;
fn deref(&self) -> &Self::Target {
&self.enforcer
}
}
impl DerefMut for casbinService {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.enforcer
}
}
pub struct casbinMiddleware<S> {
service: Rc<RefCell<S>>,enforcer: Arc<RwLock<CachedEnforcer>>,}
impl<S,B> Service<B> for casbinMiddleware<S>
where
S: Service<Response = ServiceResponse<B>,{
//type Request = ServiceRequest;
type Response = ServiceResponse<B>;
type Error = Error;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response,Self::Error>>>>;
fn poll_ready(&self,cx: &mut Context<'_>) -> Poll<Result<(),Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&mut self,req: ServiceRequest) -> Self::Future {
let cloned_enforcer = self.enforcer.clone();
let mut srv = self.service.clone();
Box::pin(async move {
let path = req.path().to_string();
let action = req.method().as_str().to_string();
let option_vals = req.extensions().get::<casbinVals>().map(|x| x.to_owned());
let vals = match option_vals {
Some(value) => value,None => {
return Ok(req.into_response(HttpResponse::Unauthorized().finish().into_body()))
}
};
let subject = vals.subject.clone();
if !vals.subject.is_empty() {
if let Some(domain) = vals.domain {
let mut lock = cloned_enforcer.write().await;
match lock.enforce_mut(vec![subject,domain,path,action]) {
Ok(true) => {
drop(lock);
srv.call(req).await
}
Ok(false) => {
drop(lock);
Ok(req.into_response(HttpResponse::Forbidden().finish().into_body()))
}
Err(_) => {
drop(lock);
Ok(req.into_response(HttpResponse::BadGateway().finish().into_body()))
}
}
} else {
let mut lock = cloned_enforcer.write().await;
match lock.enforce_mut(vec![subject,action]) {
Ok(true) => {
drop(lock);
srv.call(req).await
}
Ok(false) => {
drop(lock);
Ok(req.into_response(HttpResponse::Forbidden().finish().into_body()))
}
Err(_) => {
drop(lock);
Ok(req.into_response(HttpResponse::BadGateway().finish().into_body()))
}
}
}
} else {
Ok(req.into_response(HttpResponse::Unauthorized().finish().into_body()))
}
})
}
}
原始回购链接 - https://github.com/casbin-rs/actix-casbin-auth
我的更改 - https://github.com/smrpn/actix-casbin-auth/tree/feature/bumpactixweb
解决方法
Service
trait 有一个必需的泛型类型参数,但您没有设置它。我们在您实施 Service
(通过将其从 Service
更改为 Service<B>
)和 Transform
(通过将其从 Transform<S>
更改为 { {1}}),但是您没有在使用 Transform<S,T>
作为特征边界的地方更改它(即 Service
)。遵循也应从 S: Service<...>
更改为 S: Service<Request = ...>
的其他更改。
请注意,这将修复您提到的错误,但不会修复其他错误。我对 S: Service<B,Request = ...>
不熟悉,但从我看到的情况来看,在您应该将 actix-service
更改为 Transform<S>
,Transform<S,ServiceRequest>
为 {{ 1}} 和 Service
到 Service<ServiceRequest>