I'm looking for an elegant pattern to solve this problem:
I have several user roles in my system, and for many of my controller actions, I need to deal with slightly different data.
For example, take
/Users/Edit/1
This allows a Moderator to edit a users email address, but Administrators to edit a user's email address and password.
I'd like a design for separating the two different bits of action code for the GET and the POST.
Solutions I've come up with so far are:
Switch inside each method, however this doesn't really help when i want different model arguments on the POST :(
Custom controller factory which chooses a UsersController_ForModerators and UsersController_ForAdmins instead of just UsersController from the controller name and current user role
Custom action invoker which choose the Edit_ForModerators method in a similar way to above
Have an IUsersController and register a different implementation of it in my IoC container as a named instance based on Role
Build an implementation of the controller at runtime using Castle DynamicProxy and manipulate the methods to those from role-based implementations
Im preferring the named IoC instance route atm as it means all my urls/routing will work seamlessly.
Ideas? Suggestions?
Woo, no answers. Here's my attempt at the IoC approach, I think I'll be going with this unless anyone has any other ideas.
Segregating Controller Logic Based on User Role in ASP.NET MVC
Related
I am hoping to create some secure areas of my MVC application, I understand how users can register, login etc with the out of the box views controllers etc.
One thing that seems to be lost on me is a way to manage these users after they register. Some things I would like to be able to do:
Assign roles to users
C-R-U-D users
C-R-U-D roles
Is this all functionality I have to build myself or am I just missing something here? Everything I have found lends itself to writing code to do all these things, but it seems as though these are standard enough that they should exist.
it's very simple. if you take a look at your auto-generated DB for users, you will see that it already contains tables for roles etc. so everything was already prepared for generic use, you just need to define the basics and use it.
You can first try to play with it a bit by adding values manually to the DB tables, just to get the feel of how it works.
define a role
assign users with that role
now depending on your use, whether you'd like to allow\block access to action or entire controllers just set this for example above a action or class [Authorize(Roles = "Admin")].
in addition to (3) you can also make decisions in the server side (C# and cshtml) according to the user roles, by using:
var userManager = new UserManager(userStore);
if(userManager.IsInRole(user.Id, "Admin")){...}
read more in this link, it goes over the CRUD actions - define and use.
I am a bit new to ASP.NET MVC and I have a bit of an ordeal. I am developing a website with several roles in it and of course the logic and gui that the user gets depends on the role (duh).
There are 10 separate roles in this application. They do share most of the same functionality but some screens will be different depending on which roles they are in.
Heres my question. All examples and tutorials I've read on the internet and the Apress book that I have been reading show an example how to implement roles with one role (Admin) in which the common way is to provide an Admin Controller (or even Admin area) for the authorized section of the site. However, what if there are 10 roles? Do I really need to code up 10 separate controllers?
Let me help the question by giving detail what is being developed. There will be a menu and the menu items will be filtered by role of what views(or pages) they can and cannot get.
The from what they select, it will provide them a restricted view(or authorized page) which from within will provide a plethora of functionality limited to just that role.
I know there are several different ways to do this, I just want to know what is the recommended or "clean" way.
Have any of you been in this situation and if so, how did you organize the logic for multiple roles? Separate all roles to separate controllers? Have few controllers but just apply authorize filtering on the action methods? Apply the role filtering within the views or partial views and leave the controllers alone?
Unfortunately there are little resources for how to implement several roles out there, I just want to know how to do it the "correct" way in terms of separating the logic.
I would put the pieces of functionality into partial views. Have one controller per piece of website and load partial views based on the role and what should be exposed.
I would only stray from that if you have an excessive amount of differences, like an administrator would possible have. Then I typically make an area to encapsulate that functionality.
Regardless of the controller separation I would definitely use partial views to minimize duplication of similar code. You will reap the benefits when you need to maintain that code.
Use Authorize on the action methods and apply the roles allowed for the operation.
Depending on what's appropriate for the scenario, build a list of available actions from the controller and send that to the view as part of the view model. In some cases its more appropriate to send a simpler view model that tells the view whether each operation is allowed i.e. CanDelete, CanEdit, CanViewDetailedInfo etc.
I'd start with that, and depending on the actual complexity re-factor to any combination of:
An ActionFilter that populates the available actions / instead of explicitly doing it in the controller
Use reflector to look for the list of roles applied in authorize / so you only specify roles once
Your own html helpers that take authorization into account. So when you declare an action link, its only output when the action is supported.
There are plenty of questions (and information) on setting up asp.net membership, role providers and the like. Whether or not you should use the built in platform provided by microsoft, or role extend the base classes and role your own.
I have decided to extend the default providers and implement my own membership and role providers. Now my question, is specifically around role authentication.
Traditionally, you would create roles maybe like 'Manager, Administrator, Employee, Super User' or whatever you have. But what would/should you do with respect to permissions which I consider to be a finer grain of control? Let me elaborate....
Within my asp.net mvc site I have different areas like administration, management, messaging, reporting etc. I would crate roles for each of these like 'Administrator', 'Manager', 'Reporter' etc. Without the appropriate role, you can't gain access to that area of the site. So I would lock down the entire controllers with this at the class level.
But now take one area as an example; messaging, and say I wanted to have finer grain permissions for CRUD; create a message, view/read messages, edit messages, delete messages etc.
Finally my question. How would it be best to implement this finer grain of control? One approach I see (not sure if it is a good one), is to just create asp.net membership roles for everything. So I might have....
Messenger (broad level role), CreateMessage, ReadMessage, EditMessage, DeleteMessage.
On one hand I would like some users to be able to read/view messages. But not necessarily create or delete them. Individual controller actions could have the specific roles applied.
Do you see any problems with this approach? Do you have a better idea?
Solution So Far
I have decided to create my own schema and implement custom membership and role providers. My schema includes;
User
UserProfile
Permission
PermissionAssignment
Role
RoleAssignment
Going to be away for the next day or two but will update with more information when I get a chance.
I think you should forget about roles on the authorization mechanism, ask for permissions instead (at the end a role is an agrupation of permissions), so if you look it that way, your Authorize Attribute should ask for an entity and action, not for a particular role. Something like:
[Authorize(Entities.Message, Actions.Create)]
public ActionResult CreateMessage()
[Authorize(Entities.Message, Actions.Edit)]
public ActionResult EditMessage()
[Authorize(Entities.Message, Actions.View)]
public ActionResult ViewMessage()
That way your roles do what they do best, abstract permissions collection instead of determining a inflexible way of access level.
EDIT: To handle specific rules like the one pointed by David Robbins, Manager A is not allowed to delete messages created by Manager B, assuming they both have the required permission to access this Controller Action, the Authorize is not responsible to check this type of rules, and even if you try to check that at Action Filter level it will be a pain, so what you can do is extend the Authorize validation to the ActionResult (injecting an action parameter holding the validation result), and let the ActionResult make the logic decision there with all the arguments in place.
This is a similar question, is not exactly the case pointed out here, but its a good starting point on extending the Authorize validation with Action Parameters.
With respect to your CRUD example, aren't you really talking about authorization, and would the authorization vary between the membership roles "Manager" and "Reporter"? I think you need to create a separate mechanism for those finer grained activities if the roles do not distinguish between a read and write authorization between messages.
If you were to create a role for each action - EditMessage, DeleteMessage - what will you do in the case when Manager A should NOT be able to delete messages for Manager B?
As well as adding [Authorize(Roles="Administrator")] etc above your controller. You can also put that attribute on the indiviual Actions too
If my site has several user roles say Admin, User, Manager and there are several modules of functionality that may be used by one particular user or by all users how should I go about naming my controllers?
Is it OK to have role based controllers such as an Admin, User and Manager controller as well as controllers for shared functionality such as Products controller?
And for small parts of functionality that is used by only one user role can I keep that inside the user based controller e.g. having all the add/remove/update functionality for product categories can I have that inside the Admin controller or should it have its own controller even though it will only be a few lines of code?
When searching the net for conventions on doing this I am only provided with ways to name the actual file and other sources only explain the controller functionality and not what should and should not be a controller.
If this is subjective I am also happy to take that as an answer, but as it currently stands I am unsure of what is acceptable and whether or not role based controllers are acceptable in the MVC framework.
Personally, I have upgraded my ASP.NET MVC project to version 2-beta release 2 and moved admin related stuff to different area.
This way you can keep your controller names related to their function but run them from dedicated area.
I'm creating a new ASP.NET MVC application. So far I've used the Account controller for actions related to a user's account -- Login/Logout, Activation (like Register, but I use Register for other actions in the site so I've renamed it), Add/Update Contact information. Up to now, though, I've been concentrating on the administrative user views.
I'm at the point where I'm going to start creating the various views that non-administrative users will see. These are rather limited compared to the administrative interface. My inclination is to create a new set of views and associated controller in the User "family" instead of using the Account views/controller. Is this a good idea or should I stick with the Account controller? My feeling is that since this is for ordinary users it should be a separate controller since Account would apply to both ordinary and administrative users.
EDIT: After reading the first couple of responses, my refactored question is:
Do you consider the Account controller to be for administrative actions related to the user's account or for all actions on the user's account? Would you distinguish between membership/role related views/data and application related views/data to the extent of creating a new controller.
Related, but doesn't directly answer my question: ASP.NET MVC Account Controller usage guidelines?
I don't think there's a right or wrong answer here, so I'll give you my opinion.
Technically, either solution (extending the Account controller or creating a new controller) will work just fine.
So I think this is more a question of how the users perceive the functionality. I think it's a good idea to follow the convention that the URI dictates the controller (or vice versa, if you prefer).
If, for example, you'd like to have the "administrative" actions on a separate path, then that should be a separate controller. You might want to do this, for example, if you use an IIS module for authentication or if it makes your log analysis easier.
On the other hand, it might be the case that the users perceive account functions and administrative functions as part of the same family of actions, except that some users have additional features. If so, then that suggests that should be on the same path in the URI and, hence, part of the same controller.
Summing up, I think this is a question you should ask your user representative instead of folks on this site. :)
Update: Regarding your updated question, I would say that it is fairly natural to put an action for changing a user's password on the Account controller, and that action could be invoked by the user herself, not just an administrator. So I wouldn't presume that the Account controller is strictly for administrative tasks. On the other hand, your example of the fund-raising performance is well outside of the scope of membership-related things, so it is not clear that it belongs on Account, either. I'm still leaning towards, "ask your user representative."
In ASP.NET MVC you will usually create controls based on data types rather than access types. For example:
Instead of 2 /Controllers/UsersControl.cs and /Controllers/Admin/UsersControls.cs it is easier to use one common controller for both admins and regular users - /Controllers/UsersController.cs (by setting different [Authorize] attributes and views).
I would keep existing AccountController.cs for encapsulating account related functionality. And just add new UsersController.cs for the rest Users related functionality (which could have methods like OnlineUsers etc.)