I have the following Filter on my Controller:
[Authorize(Roles="Admin")]
public class AdminOnlyController : Controller
{
// stuff
}
I showed a couple of guys here at work what I'm doing, and a huge debate emerged with some of the guys claiming that Authorization should not be a responsibility of the Controller. This is the way I learned to do it, according to the book Pro ASP.NET MVC Framework by Steven Sanderson.
None of the other guys were able to suggest how it should be done, other than that it was wrong.
Is it? Is there a better way?
The simple answer is yes - that is the best way. The Controllers' Actions are the end point for ALL requests to the application. It makes perfect sense to put the authorisation there.
You could farm the authorisation out to IIS, but that worked better when access was controlled to files (.aspx etc). Now we have a MVC with which you have to control access to multiple actions within one controller.
There's two ways to assign authorization. The controller class or the ActionResult. As opposed to how else you could do it, I'm not very sure.
I don't really see the side of the argument where you argue against the controller managing who's authorized to invoke it. By having the authorization nearby, you follow theory (I forget the name) of 'declare it as close as you can to where you use it.'
It might depend on the background of your coworkers. If they're really used to using something like XML, then I bet they're suggesting some type of configuration file - which seems to be induced due to a more corporate type of programming.
On the flip side, There could be a benefit to extracting out authorization somewhere else (but within the application) so that it's easily modifiable, in case you end up adding a "PaidUser" for example. In that case you wouldn't have to go to every controller to update it. However, I think you end up falling into an all or nothing approach - where it's either in the controller, or it's all in some configuration file. Unless you create a scheme that your central authorization can be overridden by a controller's authorization, except at that point, you can easily lose control of who's managing what and you end up in an 'authorization soup' of sorts.
Related
I've recently started a new project and I'd like to expose an API. Should I put the API controller in a special area (e.g. API) or should I just put them along with the other controllers, or even mix the API action with all the other MVC actions in the controllers?
Aside from numerous answers I could give you, this is something really you can decide. What is logical in your case? What would be more readable?
For example my colleagues like to seperate blocks of code in a technical matter, whilst i like to seperate my systems on functionality.
Just think of yourself being someone that knows nothing of your project, you're going in there for the first time to fix a bug. Where would you expect your code to be placed?
In this case, you can either say okay i'm going to put API stuff in /ApiControllers and your logic for normal controllers in '/controllers'. You could even put controllers in '/controllers' and api controllers in /api/controllers. You can also do somthing like this: 'Users/controllersandUsers/controllers/api`.
I asked this question over on the asp.net forums, and nobody seems to know what i'm talking about. I'm not sure why that is, but I figured I'll ask here to see if there is anyone with some insight.
Back when MVC2 was released, it included a sample AccountController that wrapped the built-in Membership and FormsAuthentication classes with testable interfaces and services. I read a lot about this, and it was considered a good thing because the Membership and FormsAuthentication classes were not easily testable.
Recently, I generated a new sample project with my up to date (SP1, MVC3, Tools Update, etc..) environment and I find that the AccountController is now much simpler. Gone are the Interfaces and MembershipService and FormsAuthenticationServices. The sample now calls the Membership and FormsAuthentication classes directly.
I'm wondering if anyone knows when this happened and why? Are the testable interfaces no longer considered correct? Was there a technical reason to change this?
The best I can figure is that this happened as a part of the change to remove a possible vulnerability when passing return url's on the open url.
Any insight?
The new model resembles EF's code first approach where the AccountModel is a POCO class. Inside the new API there are no longer abstractions but direct calls to static methods such as FormsAuthentication.SetAuthCookie making this code difficult to unit test. Not something I would recommend basing your real world application code upon.
And, yes, they have fixed a vulnerability inside the LogOn method which was not verifying if the return url is a relative url before redirecting.
Personally I would recommend you using abstractions in order to weaken the coupling between your controller logic and its dependencies. This will make the code easier to unit test.
For me passing all those domain models to views without using view models are total anti-patterns and I have never bothered with them. I simply create an empty project and do the things my way. I mean in the default project they even use ViewBag for Christ sake!
The Account Controller was changed with the MVC3 tools update (When they also included the use of jQuery via Nuget)
I'm just starting to sketch up the base of a web-based system, and I would like the admin to have the possibility to limit access either by Controller or by Model. My problem is, I can't decide which one (or both?) of them I should go with. Any ideas? Pros/Cons?
First I was leaning towards doing it in the Controllers, seeing as they "control" the flow of the system. But then, thinking that the access should probably be limited by the data it accesses, not the logical part of the system, I felt like I really should go with the Model.
Now I just can't decide.. I've been bouncing back and forth for a couple of days now without actually moving forward at all, so now I turn to You, oh Great Internet, in hope for answers!
My implementation is in C# / ASP.NET / MVC2, but I'm still working "theoretically" so it's not really framework specific..
Although there could be exceptions to this, access control should be done by the controller.
The models should not be holding any procedural functionality, just business logic. Business logic on itself should not need to be access-controlled.
The controller, which contains actions that 'interact' with this business logic and models, should be the place to have access control in. Some frameworks already provide functionality for access control, that can evaluate the state of an application to decide whether a certain action can be performed.
Example:
On a web application, Model "Person" holds "persons", and has a function 'createNew (name)'
Controller 'PersonsController' has action 'addNewPerson()', which reads the name from HTTP Post and calls the function mentioned above. It also has an access rule that says that action 'addNewPerson' may not be called if the current state of the application indicates that the user requesting the action is not logged in.
User authorization is a strictly session-based concern, so that is best dealt with in the Controller. Making Models session-aware is possible, but is a violation of concerns and definitely not easy in my experience. You also have to worry about the requests being thread-safe depending on your technology stack.
The way Rails apps typically deal with this is by adding authorization functions to the Controller base class, and letting you define a before_filter to either the entire controller or the specific actions which need to authorize the request.
Typically, I would expect your users to have roles that have access to a a range of functions they can perform on a range of models. This access/no access lookup would be made in the controller.
In the current project I'm working on, we limit access at the controller level via action filters.
The action filters can be defined for a specific action if we want to limit access just to that specifically (ex. a certain page the user shouldn't see) or defined on the controller if that entire area is limited.
The action filter itself is pretty simple, and uses the HttpContext to find the user's identity, but in our case we're using form's authentication so this may differ based on what type of authentication mechanism you're using.
ASP.Net MVC Controllers have several methods of forwarding control to another controller or action. However, all of them cause a client redirect, with a 302 and a new browser request.
Why is there no internal "call another controller's action" functionality, without getting the client involved? I'm pretty sure that the php CodeIgniter framework also lacks this functionality.
The best reason that I can come up with is that ultimately it's unnecessary, since any code you want to call into could be factored out into someplace common, and in ASP.Net MVC at least, the operation might be quite expensive. But a lot of people ask about this, and it seems like it would ultimately be a convenience.
So... lots of smart people designed these frameworks. There must be some good reasons for not having this?
In Codeigniter you can set custom routes and stuff to direct certain URLs to other controllers/actions, but I think you mean in the middle of a controller function to jump into another?
If there is any business logic you have, especially if it's going to be reused, it should go into a model, not a controller. You can also specify different views in a controller depending on some condition or something. If you have repeating code that doesn't 'fit' into a model, then it should probably end up as a static helper function, or in a library class.
So yeah, I think you're right on when you say:
The best reason that I can come up with is that ultimately it's unnecessary, since any code you want to call into could be factored out into someplace common
This forces you into staying within the MVC pattern.
Best to keep your controllers lightweight anyways.
Well, at least in ASP.NET MVC, controller actions are just C# methods called in creative ways. So you can just explicitly call another controller action, like so:
Sample controller:
public class SampleController : Controller
{
public ActionResult Foo()
{
return View("foo");
}
public ActionResult ShowMeFoo()
{
return Foo();
}
}
Now, I think in most cases one wouldn't want to do this. Considering urls as a RPC interface for your app, it should forward to a different url when getting different results. Doesn't apply to all cases, but can appy to most.
I suspect it may go against the REST idea, everything is a resource. If you wish to perform a server transfer, you can as well offer an extra url for that resource. This way the client will know on that specific url he will receive one particular representation of a resource, and not under circumstances something else. That makes sense actually.
I always try to make my applications as RESTful as possible but I've recently begun working on a complex project that requires multiple additional methods in my controller.
I normally achieve this by adding another :collection to the route but it seems like a workaround and in on scenario I have 5.
Are there any best practices for handling the extra methods in a controller? They are generally simple forms that updates a model.
The other solution, which is what I do, is every time you find yourself creating an action that doesn't fit into the RESTful actions, eg Search, so you might find yourself making a search action on an Article controller, what you could do instead of creating this action is create a Search controller instead, and use RESTful actions inside of that instead. There is no rule saying you need to use all the actions, you might only need one or two, but it keeps your API RESTful and your code organised.
This is not a hard and fast rule, but I have certainly found it helpful when I try to decide where to put stuff.
I think there's a bit of confusion in the Rails community about how and where to use the word "RESTful". Strictly speaking, the only thing that can be RESTful is your web API (as railsninja already mentioned). That the code of an application that conforms to the REST conventions (the application with REST API) can usually be organized into a set of controllers (that match the resources) and methods in these controllers (that match the four verbs of the HTTP protocol) is nothing but a hint of how to keep your application clean and organized.
If we want to talk about a RESTful Rails application, we can't just talk about RESTful controllers - there's nothing RESTful about just controllers themselves. It's possible to have a complex web application with only one controller (and myriad of methods) that represents many resources and is perfectly RESTful.
That said, it's pretty OK to add more methods to your controller. Sometimes, it's good to extract some of these extra methods and create a completely new controller - make this any time you feel good about it (rule of a thumb: create new controller anytime you are able to identify it with some self-sufficient resource, ie. a resource which could exist just by itself). Sometimes though, it'd be silly to extract some resource to a different controller. Say you have a resource which has a status attribute. It makes sense to perceive this status attribute as a resource by itself and perform at least one action on it (update), but it won't make any good to extract it to a different controller.
There is a Railscast about this topic, adding custom actions to an otherwise RESTful controller.
Edit: I see that you've mentioned the method in the Railscast as a workaround already. :-) I believe the only other "pure" way to handle it would be to add additional controllers as required to support the actions you want.
"I normally achieve this by adding another :collection to the route but it seems like a workaround and in on scenario I have 5. "
This sounds perfectly fine to me. REST is not about the crud operations and your concern seems to stem from the fact that you are doing more than the basic crud operations but there's nothing wrong with that.