Return the username in a separate service

This allows us to use a service implementation which
returns a dummy user during development and the actual authenticated
user during production.  It also simplifies tests.
This commit is contained in:
Simon Goller 2024-04-26 22:41:44 +02:00
parent 789981ee92
commit 926ac006e7
3 changed files with 29 additions and 7 deletions

View file

@ -12,7 +12,15 @@ async fn main() {
let hello_dao = dao_impl::HelloDaoImpl::new(pool.clone()); let hello_dao = dao_impl::HelloDaoImpl::new(pool.clone());
let permission_dao = dao_impl::PermissionDaoImpl::new(pool); let permission_dao = dao_impl::PermissionDaoImpl::new(pool);
let permission_service = service_impl::PermissionServiceImpl::new(permission_dao.into()); // Always authenticate with DEVUSER during development.
// This is used to test the permission service locally without a login service.
//
// TODO: Implement a proper authentication service when used in produciton. Maybe
// use differnet implementations on debug then on release. Or control it via a
// feature.
let user_service = service_impl::UserServiceDev;
let permission_service =
service_impl::PermissionServiceImpl::new(permission_dao.into(), user_service.into());
let hello_service = let hello_service =
service_impl::HelloServiceImpl::new(hello_dao.into(), permission_service.into()); service_impl::HelloServiceImpl::new(hello_dao.into(), permission_service.into());
rest::start_server(hello_service).await rest::start_server(hello_service).await

View file

@ -19,6 +19,8 @@ pub trait PermissionService {
&self, &self,
privilege: &str, privilege: &str,
) -> impl Future<Output = Result<(), ServiceError>> + Send; ) -> impl Future<Output = Result<(), ServiceError>> + Send;
}
pub trait UserService {
fn current_user(&self) -> impl Future<Output = Result<Arc<str>, ServiceError>> + Send; fn current_user(&self) -> impl Future<Output = Result<Arc<str>, ServiceError>> + Send;
} }

View file

@ -33,27 +33,35 @@ where
} }
} }
pub struct PermissionServiceImpl<PermissionDao> pub struct PermissionServiceImpl<PermissionDao, UserService>
where where
PermissionDao: dao::PermissionDao + Send + Sync, PermissionDao: dao::PermissionDao + Send + Sync,
UserService: service::UserService + Send + Sync,
{ {
permission_dao: Arc<PermissionDao>, permission_dao: Arc<PermissionDao>,
user_service: Arc<UserService>,
} }
impl<PermissionDao> PermissionServiceImpl<PermissionDao> impl<PermissionDao, UserService> PermissionServiceImpl<PermissionDao, UserService>
where where
PermissionDao: dao::PermissionDao + Send + Sync, PermissionDao: dao::PermissionDao + Send + Sync,
UserService: service::UserService + Send + Sync,
{ {
pub fn new(permission_dao: Arc<PermissionDao>) -> Self { pub fn new(permission_dao: Arc<PermissionDao>, user_service: Arc<UserService>) -> Self {
Self { permission_dao } Self {
permission_dao,
user_service,
}
} }
} }
impl<PermissionDao> service::PermissionService for PermissionServiceImpl<PermissionDao> impl<PermissionDao, UserService> service::PermissionService
for PermissionServiceImpl<PermissionDao, UserService>
where where
PermissionDao: dao::PermissionDao + Send + Sync, PermissionDao: dao::PermissionDao + Send + Sync,
UserService: service::UserService + Send + Sync,
{ {
async fn check_permission(&self, privilege: &str) -> Result<(), service::ServiceError> { async fn check_permission(&self, privilege: &str) -> Result<(), service::ServiceError> {
let current_user = self.current_user().await?; let current_user = self.user_service.current_user().await?;
if self if self
.permission_dao .permission_dao
.has_privilege(current_user.as_ref(), privilege) .has_privilege(current_user.as_ref(), privilege)
@ -64,7 +72,11 @@ where
Err(service::ServiceError::Forbidden) Err(service::ServiceError::Forbidden)
} }
} }
}
pub struct UserServiceDev;
impl service::UserService for UserServiceDev {
async fn current_user(&self) -> Result<Arc<str>, service::ServiceError> { async fn current_user(&self) -> Result<Arc<str>, service::ServiceError> {
Ok("DEVUSER".into()) Ok("DEVUSER".into())
} }