Mi enfoque puede no ser ideal, pero creo que funciona bastante bien. Cosa que hice - Decidí no
usar la inyección de dependencia
pasar al usuario actual en todas partes directamente porque eso se volvía demasiado engorroso y cambiaba al contexto estático. Problema con contextos: son un poco difíciles de manejar.
Ésta se define en mi dominio:
public static class UserContext{
private static Func<User> _getCurrentUser;
private static bool _initialized;
public static User Current{
get{
if(!_initialized)
throw new Exception("Can i haz getCurrentUser delegate?");
var user=_getCurrentUser();
return user??User.Anonymous;
}
}
public static void Initialize(Func<User> getCurrentUser){
_getCurrentUser=getCurrentUser;
_initialized=true;
}
}
Nota que el delegado es estática - para la aplicación conjunto sólo uno a la vez. Y no estoy 100% seguro de su ciclo de vida, posibles fugas de memoria o lo que sea.
La aplicación de cliente es responsable de inicializar el contexto. Mi aplicación web hace que en cada petición:
public class UserContextTask:BootstrapperTask{
private readonly IUserSession _userSession;
public UserContextTask(IUserSession userSession){
Guard.AgainstNull(userSession);
_userSession=userSession;
}
public override TaskContinuation Execute(){
UserContext.Initialize(()=>_userSession.GetCurrentUser());
return TaskContinuation.Continue;
}
}
Usando mvcextensions biblioteca de tareas bootstrapping corriente de línea. Solo puede suscribirse para acordar eventos en global.asax para eso.
En el lado del cliente (aplicación web), que implementan servicios de aplicaciones nombrado IUserSession:
public User GetCurrentUser(){
if(HttpContext.Current.User==null) return null;
var identity=HttpContext.Current.User.Identity;
if(!identity.IsAuthenticated) return null;
var user=_repository.ByUserName(identity.Name);
if(user==null) throw new Exception("User not found. It should be. Looks bad.");
return user;
}
Hay algunos más lame code necesaria con el fin de utilizar formularios de autenticación con funciones w/o proveedor de proveedor de pertenencia y el papel. Pero ese no es el punto de esta pregunta.
A nivel de dominio - que estoy describiendo explícitamente permisos que los usuarios podrían tener como éste:
public class AcceptApplications:IUserRights{
public bool IsSatisfiedBy(User u){
return u.IsInAnyRole(Role.JTS,Role.Secretary);
}
public void CheckRightsFor(User u){
if(!IsSatisfiedBy(u)) throw new ApplicationException
("User is not authorized to accept applications.");
}
}
Lo interesante es - esos permisos se pueden hacer más sofisticado. Por ejemplo:
public class FillQualityAssessment:IUserRights{
private readonly Application _application;
public FillQualityAssessment(Application application){
Guard.AgainstNull(application,
"User rights check failed. Application not specified.");
_application=application;
}
public bool IsSatisfiedBy(User u){
return u.IsInRole(Role.Assessor)&&_application.Assessors.Contains(u);
}
public void CheckRightsFor(User u){
if(!IsSatisfiedBy(u))
throw new ApplicationException
("User is not authorized to fill quality assessment.");
}
}
permisos se puede comprobar vica versa también - El usuario tiene estos muchachos:
public virtual bool HasRightsTo<T>(T authorizationSpec) where T:IUserRights{
return authorizationSpec.IsSatisfiedBy(this);
}
public virtual void CheckRightsFor<T>(T authorizationSpec) where T:IUserRights{
authorizationSpec.CheckRightsFor(this);
}
Aquí está mi agregada clase base de la raíz:
public class Root:Entity,IRoot{
public virtual void Authorize(IUserRights rights){
UserContext.Current.CheckRightsFor(rights);
}
}
Y aquí es cómo comprobar los permisos:
public class Application{
public virtual void Accept(){
Authorize(new AcceptApplications());
OpeningStatus=OpeningStatus.Accepted;
}
}
Espero que ayude ...
Solo quería señalar que hay una pequeña superposición con mi pregunta que he preguntado más recientemente sobre permitir que los repositorios conozcan el contexto del usuario. He intentado resolver este problema junto con el uso del contexto del usuario para acceder a otros valores sensibles al contexto del usuario. http://stackoverflow.com/questions/5374176/can-ddd-repositories-be-aware-of-user-context – jpierson