Authorisation exceptions - asp.net-mvc-3

I've tagged my controller with an authority annotation but would like to exempt one of the methods... can that be done? how?
[Authorize(Roles="Admin")]
public class ProductController : Controller
{
[DEAUTHORIZE]
public ActionResult Start(int it)
{ ... }

In MVC 4 was introduced AllowAnonymousAttribute which tells action invoker to skip AuthorizeAttribute.
[AllowAnonymous]

No, this can't be done. The standard way to achieve this is to simply move the Start action out in a separate controller. Another possibility consists into building a custom IFilterProvider which will apply the authorization attribute conditionally instead of baking it manually into the ProductController. For example NInject uses this and provides a pretty fluent syntax into configuring action filters. You can conditionally apply them based on the current context.

Related

Request body field processing in spring

I am working on a spring base web application where, we have a few RestControllers and some Request DTO classes. Request DTO contains a token field which needs some validation. So I used spring validators to validate that. After validation, we want to send that field to an external system using another REST API (Just for some kind of analytics logging). The same field is repeated in multiple DTO objects and their controllers. So, I am easily able to define annotations for validators and reuse them across the DTOs. But I am not sure how to process that field after validation succeeds (i.e. call analytics API to consume that field post validation), without mixing it with the core logic of controllers.
Approaches I could think of:
Implement a filter/interceptor and process the field there. But then
there is a limitation that request body can be read only once so I
need to use some alternate ways by creating request wrappers.
Repeat the logic in every controller and it is very error prone as for
every new controller we need to remember to write that code.
But non of these approaches look cleaner. Can someone recommend a better way to achieve that?
Thanks in advance.
You can create a BaseController and implement the method there. Extend this BaseController wherever you need this logging service. Like below.
BaseController.java
class BaseController {
protected void remoteLogging(String name,String token) {
//Calling the remote log services}
}
AppController.java
#Controller
#RequestMapping("register")
public class LeaseController extends BaseController {
#PostMapping("new")
public String new(#Valid #ModelAttribute("registration") Registration registration,BindingResult result){
if(rest.hasErrors(){
remoteLogging("name","token");
}
}

How to store variables in all pages requestScopes within Spring

I usually add objects in my jsp requestScopes using Controllers.
For example, if I need to list categories in "localhost/products/viewall", I simply change my ProductsController adding something like
#RequestMapping("/products/viewall")
public void viewCategories(Model model) {
List<Category> categories = service.findAllCategories();
model.addAttribute("categories", categories);
}
so, this method adds a list of categories to my requestScope.
I need to do the same, but for all the pages of the website (since the variable I need will be used in the layout of the site).
How can I add something to all the pages requestScopes with Spring?
I think you have at least two possible options for this:
Using an MVC Interceptor. With an interceptor you can perform common operations for all requests. You can extend HandlerInterceptorAdapter and add common model data in postHandle
Using the #ModelAttribute annotation within an Controller. You can use this to add common data for all request mappings within a controller. You can also use an #ControllerAdvice (with #ModelAttribute annotated methods inside) if you want provide model data to all controllers. The section Using #ModelAttribute on a method should provide some additional information for this.

ASP.NET WebAPI: Generic controller for OData endpoint

I'm currently experimenting with OData endpoints in ASP.NET MVC 4 Web API. I like the concept and try to come up with efficient ways to use it in our project.
One question I have is the following: we have a service that is able to return an IQueryable and takes the name of an entity as Input:
public IQueryable GetAll(string entityName);
In standard Web API (as opposed to OData Controllers) I can create a generic controller, that can be called in the form /api/entities/{entityName} and returns the IQueryable.
In case of an OData Controller, I carry out the following entity-specific steps:
Register the entities in the model.
Create a separate Controller for each entity that derives from EntitySetController<>.
I want to use the generic service and avoid as much entity-specific implementations as possible. The first step can easily be automated if the service can return a list of the entities and the corresponding types.
That leaves step 2, because up to now I need to create a specific controller for each entity. I also want to avoid that and create a generic controller that uses the generic service.
Can anyone recommend a solution, maybe by influencing OData routing?
You can create a custom routing convention that selects the same controller no matter what the entity set is. Example,
public class CustomControllerRoutingConvention : IODataRoutingConvention
{
public string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
{
return null;
}
public string SelectController(ODataPath odataPath, HttpRequestMessage request)
{
return "SomeFixedContrllerNameWithoutTheControllerSuffix";
}
}
You can register that routing convention using the following code,
IList<IODataRoutingConvention> routingConventions = ODataRoutingConventions.CreateDefault();
routingConventions.Insert(0, new CustomControllerRoutingConvention());
config.Routes.MapODataRoute("OData", "odata", builder.GetEdmModel(), new DefaultODataPathHandler(), routingConventions);
I came up against the same problem, and ended up writing a custom IHttpControllerSelector instead of an IODataRoutingConvention. IODataRoutingConvention looks like a good option if your generic controller doesn't require generics :) . But since IODataRoutingConvention.SelectController() only returns a string, I don't see how it will work for instantiating a controller with generic type parameters.
I decided this problem needs a good, general-purpose, open-source solution - so I created one: https://github.com/EntityRepository/ODataServer . It's prerelease now, but I'm currently doing a lot of work on it. I think there's more to it than just choosing the right controller, there are general patterns to define for shared controllers, and by default Web API OData expects strongly typed and strongly named navigation properties which makes it challenging to create a re-usable implementation.

How to map a path to multiple controllers?

I'm currently working on a spring based web application and have a special requirement that seems not (at least not out of the box) be provided by spring MVC. The application serves data for multiple users each organized in their own "company". Once a user has logged in, I'm able to identify to which company he belongs to.
The application itself is built with multiple "modules", each with it's own domain objects, DAO, Service and Controller classes. The idea behind this concept is that I can for example extend a certain controller class (let's say to use a different service class) based upon the user and here is my problem.
Since i do not want to change my request paths for certain users, I'm currently looking for a way how to serve a request issued on a certain request path with different instances of a controller based upon the user issuing the request.
I came up with the idea to attach a HTTP Header Field for the company
Example:
X-Company:12345
and have my controllers configured like this:
#Controller
#RequestMapping(value="/foo/")
public class FooController {
// ...
}
#Controller
#RequestMapping(value="/foo" headers="X-Company=12345")
public class SpecialFooController extends FooController {
// ...
}
However this is not possible, since spring MVC treats each header (except Content-Type and Accept) as a kind of restriction, so in my case it would handle all requests with the FooController instead of the SpecialFooController unless i add a "headers" restriction on the FooController as well, which is not practicable.
Is there some way how to customize this behaviour or some direction one could point me to look for? Or maybe someone has another idea how to achieve this. It'll be highly appreciated.
Thanks!
I'am not sure but I think you can do this with HandlerMapping. Have a look at the documentation
To take your own suggestion, you can use the #RequestHeader annotation in your controller methods:
#Controller
public class MyController {
#RequestMapping("/someAction")
public void myControllerMethod(#RequestHeader('X-Company-Id') String companyId) {
}
}
Or you could use #PathVariable:
#Controller
public class MyController {
#RequestMapping("/{companyId}/someAction")
public void myControllerMethod(#PathVariable("companyId") String companyId) {
}
}
Using this approach would mean that it is in fact different URLs for each company, but if you can set the company id header, I guess you also can suffix the URLs with the company id.
But there are also other possibilities. You could write an interceptor that puts the company id in a session or request variable. Then you wouldn't have to add the annotation to every controller method. You could also use a subdomain for each company, but that wouldn't look too pretty if the company id is a random alphanumeric string. E.g: companyone.mydomain.com, companytwo.mydomain.com
Edit
#RequestMapping can be added to the controller level as you know, so you should be able to do
#Controller
#RequestMapping("/controller/{companyId}")
as the base url, if that's a better option.
I was able to meet the requirement by making usage of a customized RequestCondition. By defining your own annotation that can be placed at the type and method level of a controller. Extending the RequestMappingHandlerMapping by your own implementation and overriding the getCustomTypeCondition() and getCustomMethodCondition() methods translates a controller annotation into your own RequestCondition.
When a request comes in, the custom RequestCondition will be evaluated and the annotated controller(method) will then be called to serve the request. However this has the downside, that one needs to remove a servlet-context.xml file and switch to the WebMvcConfigurationSupport class instead in order to be able to use your customized RequestMappingHandlerMapping class.
This question was also discussed here.
Edit:
A pretty good example using this can be found here.

MVC Autofac ExtensibleActionInvoker stops me using interface parameters

I have a problem with the Autofac ExtensibleActionInvoker interacting with the MVC ModelBinder when using interfaces for parameters. The background is as follows:
I am building a MVC application and I am using Autofac MVC3's ExtensibleActionInvoker to inject my services as parameters to my actions, e.g.
public ActionResult Test( IMyService service)
{
//A new instance of service is created by Autofac ExtensibleActionInvoker
return View();
}
This works really well and makes for a really clean design (see Alex Meyer-Gleaves post for more information on this approach). I want to use this method as I am producing a code generator to create actions, views, services and DTOs and a per-action service approach makes this easier.
However I also want to use interfaces for the parameters in action classed which receive input from an HttpPost action. This is because I use DI to create classes outside each layer. If I change the DefaultModelBinder to use DI to create the class (see page 595 of Steve Sanderson's book on MVC3 on how to do this) this this works fine, e.g.
[HttpPost]
public ActionResult Test(ITestClass dataComingFromView)
{
//model binder creates the class via DI and then binds it to the data from the post
return View();
}
However in the above simple example above I get a conflict with the ExtensibleActionInvoker enabled, i.e.
Without ExtensibleActionInvoker enabled the method above works fine, i.e. the extended
DefaultModelBinder uses DI to create the TestClass class and modelbinder binds
input from the view to the fields in the class.
With ExtensibleActionInvoker enabled it does not work, i.e. I get an empty TestClass class with no binding. I assume the ExtensibleActionInvoker takes precedence over the model binder and just creates an empty TestClass class.
(Just for completeness I should say that if I just use MVC "out of the box", i.e. no new DefaultModelBinder and no ExtensibleActionInvoker enabled, then it says you cannot use an interface as an Action method parameter.)
My question for anyone with better Autofac knowledge than me is: can I change the Autofac ExtensibleActionInvoker to select what it binds to? All my injected service classed start with IService so I could filter on that. I know you can do that in Autofac elsewhere but couldn't see anything to do that with ExtensibleActionInvoker, but maybe I missed it.
Any help would be appreciated.
Jon Smith - Selective Analytics
You are correct that the problem is caused by the ExtensibleActionInvoker class. If you look at the source for it, there is a method called GetParameterValue(). See below:
protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
if (_injectActionMethodParameters)
return _context.ResolveOptional(parameterDescriptor.ParameterType) ?? base.GetParameterValue(controllerContext, parameterDescriptor);
return base.GetParameterValue(controllerContext, parameterDescriptor);
}
This method overrides the method that eventually uses the MVC framework's model binder infrastructure. What this means, is that the ActionInvoker tries to resolve the parameter using AutoFac first, and if it fails, falls back to the default functionality. Based on the results you are getting, it seems that your AutoFac configuration must be setup to provide a default resolution of ITestClass.
In order to register a custom ModelBinder with AutoFac you have a couple options. You can decorate the view model with a ModelBinderTypeAttribute or you can do it in your configuration with the custom extension methods found in RegistrationExtensions.
One article I found looks like it provides an easy solution to a similar issue (see the end), but I have not tested this personally.
Having now worked on this problem I found a simple answer. My problem was due to me not really understanding how the MVC Model Binding worked.
If you look at my orginal problem I had created a DefaultModelBinder to allow me to use interfaces as my model parameters (see original question at the top). This was added after me including the Autofac's ExtensibleActionInvoker to bind my IService types. The problem was that the two DI approaches clashed.
The answer was that the DefaultModelBinder was sufficient to bind both my data classes and the Service definitions, so I do not need Autofac's ExtensibleActionInvoker. For completeness I have included the DefaultModelBinder code in case it is useful to anyone else.
public class DiModelBinder : DefaultModelBinder
{
protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
{
return modelType.IsInterface
? DependencyResolver.Current.GetService(modelType)
: base.CreateModel(controllerContext, bindingContext, modelType);
}
}
Note that I only call the DependencyResolver if the modeltype is an interface as I don't pass abstract classes between layers. Any alternative is to always call the DependencyResolver and then call the base.CreateModel if the DI does not resolve the type. I didn't do this because calling the DependencyResolver is slightly expensive so I only call it when I know I need it.

Resources