How to specify restrictions to user in domain driven.
I am using asp.net web api application and that application service uses from web api.
[ApiController]
public class TicketController : ControllerBase
{
....
....
[HttpPost]
[Route("change-date")]
public async Task<IActionResult> ChangeTicketDate(TicketChangeCommand command)
{
var response = await _ticketService.ChangeTicketDate(command, User.Identity.Name);
return Ok(response);
}
....
....
}
To prevent the tickets, I am sending the authenticated username to _ticketService. Because a user may change another user ticket. So I have two rules for ticket date change logic.
1- User should be owner of ticket.
2- Or User sholud be in Administrator role.
(These rules also will be using other services. For example User can only change his own password.)
public class TicketService : ITicketService
{
....
public TicketChange ChangeTicketDate(TicketChangeCommand command, string requestedUsername){
// 1. Check requested user is ticket creator or Administrator
}
....
}
To check the user role and owner, should I create a domain service? Should I create a domain authorization service to check roles?
As I see this in DDD you should have some method in your DomainModel class to do this operation e.g. ChangeTicketDate
Now if you store the information of the ticket creator when you create the ticket "which I believe you do" the validation should be part of DomainModel itself e.g.
ChangeTicketDate(string userName)
then the DomainService "Or ApplicationService" should just pass this value to the Domain Model class and the validation should be in the Domain Class
However, in some cases you may need to implement some validations before the domain model or let's say it's not related to the Entity itself, those validations should be in your Application Service
I guess the following piece of code will explain my idea better
public class TicketService : ITicketService
{
// ....
// I expect that you'll be able to get some information about the current user
public CurrentUserData CurrentUser {get; private set;}
public TicketChange ChangeTicketDate(TicketChangeCommand command){
// 1. Load the Aggregate Root from the Data StoreCheck
var ticket = db.GetById(ticketId);
// 2. Do some Application level checks
// 3. Check if the current user is Admin
if(CurrentUser.IsAdmin)
ticket.ChangeTicketDate();
else
ticket.ChangeTicketDate(CurrentUser.Username);
}
....
}
//Example of Domain Model class
public class Ticket : Entity<Guid>
{
public UserInfo Creator {get; private set;}
public void ChangeTicketDate(string requestedUsername){
if(!string.IsNullOrEmpty(requestedUsername) && requestedUsername != Creator.UserName)
threw new ValidationException("You're not allowed to do ChangeTicketDate");
}
....
}
Related
currently i am working on DMS project in which user can save and retrieve documents.
now i want to set a permission for each user at service level. now i am able to catch each user request in which i got the link of the request,user name and his roll,userid. suppose i have a three roles one is admin which has all permissions and second roll is supervisor.so supervisor can create a user and assign department to assign a department it uses i.e item/assigndepartment. and third roll is clerk i want to restrict to create a user but he can access the department list on department section not in user. to display department list i am using the same request link i.e item/assigndepartment. so how to handle this situation. :(
is it good to store the each roll specific link into table and then check for each request ???
here is my structure.
public class IdentityBasicAuthenticationAttribute : Attribute,
IAuthenticationFilter
{
public string Realm { get; set; }
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
if (context.Request.RequestUri.LocalPath == "/Login/UserLogin")
{
return;
}
// here i am catching the each request from which i am getting the user name,roll and user id.
}
}
and the controller
public class ItemController : ApiController
{
//item/assigndepartment
[HttpPost]
public CategoryList assigndepartment(Departments dept)
{
catList = _itemsModel.assigndepartment(dept);
return catList;
}
}
and model
public class ItemModel
{
publiv void assigndepartment()
{
\\ DB Logic
}
}
If you are building RESTful API, you should have GET and POST methods to item/assigndepartment. Than you can restrict both actions in the controller to their respective roles.
If you are building web app, you can create partial views or view components and render each component depending on the user role.
I've currently got a very simple setup running. This setup consists of an entity-framework project, and an IIS server. The IIS is configured to use windows authentication.
Now in my project, I want to allow only certain users to gain access to certain controllers. Within the organisation I'm working for there's a "permissions" system, a table that contains what users are allowed to access what data. So, I want to get the e-mail with which the user logged in, and check that against the database to see if he has permission.
My plan for doing this was to make a seperate piece of code, that's not accessable from the web, that contains the function "boolean hasPermissions(String email, byte permissions)". But I've got no idea where to place this, nor can I find any information on this. Is what I have in mind the right approach? And if, then how to execute this approach correctly?
You should use windows authentication, using IPrincipal , you will have a user object that you could ask IsInRole for specific role based security instead of bits / booleans
read all about it at Asp.net windows authentication
and how to implement IPrincipal Implement custom security
Code sample:
User object:
public class User : IPrincipal
{
private readonly IPrincipal _user;
public IIdentity Identity { get; private set; }
public User (IPrincipal user)
{
Identity = user.Identity;
_user = user;
}
public bool IsInRole(string role)
{
return _user.IsInRole(role);
}
}
In MVC add a filter
public class CustomAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
var user= new User (HttpContext.Current.User);
Thread.CurrentPrincipal = user;
}
}
And add that filter to your FilterConfig using
filters.Add(new CustomAuthenticationAttribute());
Then, when using the user object within your application
var user = new User(Thread.CurrentPrincipal);
if(user.IsInRole("admin")) /* do the choka choka */;
I'm creating a practice admin application using MVC4, but I'm not sure the best method to persist the logged in user data for the entire lifetime of the session so that it will be accessible to all views & controllers.
For example, I desire a user to log in, then download the user data from the database, and for the entire session I want to maintain the User model (Name, Database ID etc) so that it's accessible throughout the entire web application until the user is logged out.
Is the best approach to store this data in an encrypted cookie? Or is there a way of using a Static Class?
Currently I've read about using ViewModel Base class like so:
public abstract class ViewModelBase
{
public UserModel User { get; set; }
}
Then all of my ViewModels can inherit the base class, thus providing access to the user data model:
public class AllEmployeesViewModel : ViewModelBase
{
public List<EmployeeModel> Employees { get; set; }
}
However, if in one Controller action I set the user data, it will only be lost when loading another Controller Action.
To me it seems a waste of resources & will increase load times to have to keep downloading the user data from the database in every action.
All advice is much welcome for this new web programmer. If I've missed any important details, please do request it and I will try my best to answer.
You should look into SessionState to store data for the duration of the user's browser session.
http://msdn.microsoft.com/en-us/library/vstudio/ms178581(v=vs.100).aspx
I would abstract the Session for you application in a class in a way it is accessible to your controllers. Maybe an web application core class.
namespace MyApplication.Core
{
public class MySession
{
private const string _SessionName = "__MY_SESSION__";
private MySession() { }
public static MySession Current
{
get
{
MySession session =
(MySession)HttpContext.Current.Session[_SessionName];
if (session == null)
{
session = new MySession();
HttpContext.Current.Session[_SessionName] = session;
}
return session;
}
}
public UserModel CurrentUser { get; set; }
}
}
Somewhere in your login controller logic path
public void SomeLoginFunction(string userName,string password)
{
//DO AUTHENTICATION STUFF
MySession.Current.CurrentUser=aCurrentUserFromDB;
}
In your base class
public class ViewModelBase
{
public UserModel User { get{return {MySession.Current.CurrentUser;} }
}
I am using the repository and unit of work patterns and dependency injection to access the database with entity framework 5 in my web application. I have a User class from which Entity Framework generates a Code-First database.
public class User
{
public Guid UserId { get; set; }
public string UserName { get; set; }
.
.
.
public string LanguagePreference { get; set; }
public virtual List<Role> Roles { get; set; }
public virtual List<Branch> Branches { get; set; }
}
I have a UserService class that is used to Add or Update users. This class takes an IUserUnitOfWork as a parameter in the constructor and Unity injects a UserUnitOfwork. The IUserUserOfWork contains an IRepository<User>, an IRepository<Location> and an IRepository<Role>. These are set as Repository<T> by the DI bootstrapper. The IUserUnitOfWork sets up the different Repositories with the same entity framework DbContext. I did this as I was having issues updating the many-to-many relationships related to the User (Locations and Roles).
UserUnitOfWork:
public IRepository<Branch> BranchRepository {get; set;}
public IRepository<Role> RoleRepository { get; set; }
public IRepository<User> UserRepository { get; set; }
public DbContext Context { get; set; }
public UserUnitOfWork(DbContext context, ITransientErrorDetectionStrategy errorDetectionStrategy,RetryStrategy retryStrategy )
{
Context = context;
BranchRepository = new Repository<Branch>(context, errorDetectionStrategy, retryStrategy);
RoleRepository = new Repository<Role>(context, errorDetectionStrategy, retryStrategy);
UserRepository = new Repository<User>(context, errorDetectionStrategy, retryStrategy);
}
The Repository class then uses Entity Framework 5 to access the database.
Example of method from Repository.FirstOrDefault:
public virtual T FirstOrDefault(Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "")
{
T result = null;
_retryPolicy.ExecuteAction(() =>
{
IQueryable<T> entities = GetHelper(filter, orderBy, includeProperties);
result = entities.FirstOrDefault();
});
return result;
}
And Update from Repository:
public virtual void Update(T entity)
{
if (_dbContext.Entry(entity).State == System.Data.EntityState.Detached)
{
_dbContext.Set<T>().Attach(entity);
_dbContext.Entry(entity).State = System.Data.EntityState.Modified;
}
}
So my problem now is that when I update the User it correctly updates the data in the database, and when I log out and log in the initial change works. However if I update again and log out and in the new change isn't picked up even though the database is updated.
I'm beginning to fear that the approach I've taken is incorrect, can someone tell me how to make sure that when I do an update Entity Framework will always get the latest version?
EDIT:
So I've created a Per Request Lifetime Manager like so:
public class PerHttpRequestLifetimeManager : LifetimeManager
{
private readonly object key = new object();
public override object GetValue()
{
if (HttpContext.Current != null &&
HttpContext.Current.Items.Contains(key))
return HttpContext.Current.Items[key];
else
return null;
}
public override void RemoveValue()
{
if (HttpContext.Current != null)
HttpContext.Current.Items.Remove(key);
}
public override void SetValue(object newValue)
{
if (HttpContext.Current != null)
HttpContext.Current.Items[key] = newValue;
}
}
In my DI bootstrapper I now setup my domain context like below:
container.RegisterType<DbContext, DomainContext>(new PerHttpRequestLifetimeManager());
It still doesn't appear to be working, am I missing something else or am I setting it up incorrectly?
EDIT 2:
Just to point out the architecture:
We have an MVC application which uses Angular JS to make ajax calls to a Web Api service layer. The Web Api has an ISomethingService injected into it. It is this ISomethingService that has the repositories injected into it. Would there be some confusion for the PerHttpRequestLifetimeManager since there is both an MVC and Web API project running?
EDIT 3:
An example of how I am saving the edited user:
We have a UserModel class that is used for communications between the ServiceLayer -> API -> UI layer and back. The User class is the one generated by Entity Framework code first. The EditUser method in the UserService takes in a UserModel.
I then user the _unitOfWork.UserRepository to get the corresponding database user
var editedUser = _unitOfWork.UserRepository.FirstOrDefault(x => x.UserId == userModel.UserId);
I map the fields from the userModel to the editedUser and I then call (in the UserService)
_unitOfWork.UserRepository.Update(editedUser)
and after
_unitOfWork.Save()
YET ANOTHER EDIT:
So I have edited a simple method that updates a single text field on the user table (Language Preference). I explicitly call the dispose method after the update to ensure I am disposing the method.
public void SetUserLanguagePreference(Guid userId, string language)
{
var user = _unitOfWork.UserRepository.FirstOrDefault(x => x.UserId == userId);
user.LanguagePreference = language;
_unitOfWork.UserRepository.Update(user);
_unitOfWork.Save();
_unitOfWork.Dispose();
}
UnitOfWork.Dispose() calls the dispose method of the repositories and the Dbcontext
The database updates correctly. However the behaviour is still incorrect. When I log out and in first it retrieves the correct value. When I change it again and log out and in again it doesn't update. This has been the pattern before, it get the first update after I log out and in, but if I change again and log out and in it doesn't pick it up.
Finally, not an edit but an answer! We use Claims based authentication and have a class that overrides the ClaimsPrinciple Authenticate method that is called whenever a user is authenticated.
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal.Identity.IsAuthenticated)
{
//Check here if the authenticated user has access to this system
//using the user repository and if so add more claims to the token
}
return base.Authenticate(resourceName, incomingPrincipal);
}
It was not possible to inject into this method using DI as it always went to the empty constructor (not sure why but that's the way it is).
So instead we were setting the repository in the empty constructor like so:
public PRAuthenticationManager()
{
_userRepository = DiBootstrapper.Container.Resolve<IRepository<User>>();
}
When the Authenticate method is called we check our database for a user with the claims attached to the ClaimsPrincipal. If we make a match we add new claims to the token which are then used for each call to the Web Api later. This repository was not being disposed (even if all the others were) and so when a user logged out and in they got data from that same context which had not been disposed from the last time the user logged in.
Three full days trying to find that one....
See if this helps: How do I get Entity Framework 5 to update stale data
I ran into the same problem, it doesn't refresh from the database if you already have the object in your ObjectContext, of course, this would only work on a per object basis, but that might be just what you need.
I have found out that I need the current logged in user data in nearly every class (controllers, view, HTML helpers, services and so on). So I thought about to create an "Ambient Context" instead of injecting an IUserService or the User directly.
My approach looks something like that.
public class Bootstrapper
{
public void Boot()
{
var container = new Container();
// the call to IUserService.GetUser is cached per Http request
// by using a dynamic proxy caching mechanism, that also handles cases where we want to
// invalidate a cache within an Http request
UserContext.ConfigureUser = container.GetInstance<IUserService>().GetUser;
}
}
public interface IUserService
{
User GetUser();
}
public class User
{
string Name { get; set; }
}
public class UserContext : AbstractFactoryBase<User>
{
public static Func<User> ConfigureUser = NotConfigured;
public static User ActiveUser { get { return ConfigureUser(); } }
}
public class AbstractFactoryBase<T>
{
protected static T NotConfigured()
{
throw new Exception(String.Format("{0} is not configured", typeof(T).Name));
}
}
Example usage:
public class Controller
{
public ActionResult Index()
{
var activeUser = UserContext.ActiveUser;
return View();
}
}
Is my approach correct or do I missing something? Do you have better solutions in mind?
UPDATE:
More Detail of the User class:
public class User
{
string Name { get; set; }
bool IsSuperUser { get; set;}
IEnumerable<AzManOperation> Operations { get; set}
}
In Controllers we need to check if an User is a SuperUser to only provide the SuperUser some extra functionality.
public class BaseController : Controller
{
private readonly IUserService _userService;
BaseControler(IUserService userService)
{
_userService = userService
}
public User ActiveUser
{
get { return _userService.GetUser(); }
}
}
In Views we check Operations to only show an edit or delete button if the user has the right to do so. A view never uses the DependencyResolver, but ViewBag or ViewModel. My idea here is to implementing a custom ViewBasePage and providing an ActiveUser property, so that Views have an easy accesss.
In HtmlHelpers we render controls depending on IsSuperUser and Operations (passing in the User object or using DependencyResolver).
In Service Classes we need those properties too. For instance to decide if a basket is valid or not (check if the User is allowed to buy articles that are not in a standard list). So the Service class depends on IUserService and calling GetUser().
In Action Filters to force the user to change his password (only if it is not a SuperUser and User.ForcePasswordChange is true). Here we use the DependencyResolver.
My wish is to have a more easily way to get the User object, instead of using DependencyResolver.Current.GetService().GetUser() or using things like ViewBag.ActiveUser = User.
The User object is an object that is almost everywhere needed to check permissions or the like.
In Views we check Operations to only show an edit or delete button if the user has the right to do so.
The view should not do this check. The Controller should return a view model to the view that contains boolean properties that state whether those buttons should be visible. Returning a bool with IsSuperUser already moves to much knownledge into the view. The view shouldn't know that it should show a certain button for a super user: that's up to the controller. The view should only be told what to display.
If almost all views have this code, there are ways to extract repetitive parts out of your views, for instance with partial views. If you're finding yourself repeating those properties over many view models, perhaps you should define an envelope view model (a generic view model that wraps the specific model as T). A controller can create its view model, while you create a service or cross-cutting concern that wraps it in your envelope.
In Service Classes we need those properties too. For instance to decide if a basket is valid or not
In this case you are talking about validation, which is a cross-cutting concern. You should use decorators to add this behavior instead.
This is MVC, right?
You're reinventing the wheel.
Add this method to your Global.asax.cs:
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
var ticket = FormsAuthentication.Decrypt(authCookie.Value);
var user = ticket.Name;
var identity = new GenericIdentity(user, "Forms");
var principal = new GenericPrincipal(identity, null);
Context.User = principal;
}
}
This example shows forms authentication which you can strip if you're using another mechanism. The key is these three lines:
var identity = new GenericIdentity(user, "Forms");
var principal = new GenericPrincipal(identity, null);
Context.User = principal;
GenericIdentity and GenericPrincipal can be replaced with anything you want as long as they implement the (trivial) IIdentity and IPrincipal interfaces. You can create your own implementations of these classes with whatever extra properties you need.
You can then access the authenticated user from all the things you listed - controllers, views, etc. - via HttpContext.Current.User (which is static).
If you created your own implementation of IPrincipal you can just cast that reference to your custom type.
You'll note that IPrincipal has a method called IsInRole, so you'd say:
if (HttpContext.Current.User.IsInRole("SuperUser"))
TL;DR - you are overengineering something ASP.NET has already solved, and I'd have an aneurysm if I saw the types you're proposing in a production application.
I think the easiest and maintainable solution is to create a static class CurrentUserProvider which has only one method Get(HttpContextBase) that returns the current user, behind the scene you can use the DependencyResolver to get the service that actually returns the user. Then where you need the CurrentUser you can call CurrentUserProvider.Get(context) and do whatever custom logic you need to perform.
The other solution that you are trying to do is injecting the service in the base controller constructor which is okay if you have handful of controllers, it would become an issue if you have quite a number of controllers and not all of the controllers requires that service. Writing tests for those controller would be such pain in the neck, because you have to create stubs/mocks for that service for all your controller tests. Maybe you can use property injection instead of constructor to address it.
You can use the same property injection for Filters too.
Now, the remaining two are the view and the helper. For View you can create special base class that inherits from WebViewPage/ViewPage and use the IViewActivator to inject the service and the same applies for the helpers, create helpers that inherits from system helpers and use those in your base controllers and views.
I think the second approach is bit cumbersome and it does not add that much value to do all those custom things.
So my suggestion is to go with the first.