I have an interceptor in which i want to do some intercepting logic based on the annotation on a controller method (Not on controller class). Say want to restrict the access to that controller method for certain users only. Is there any way to get the Handler method (Yes not the handler class) in the HandlerInterceptor?
I'm afraid not. You would have to group the desired methods in one (or a few) classes and base your check on the class, rather than method.
I guess you can parse the annotations yourself and match the paths, or try to see what spring does to do so in its classes, but that would be more complicated and error-prone.
You can try (but I haven't used it, so I don't know if it works) the #Interceptors annotation on your methods (saw it here)
You can do this in Spring 3.1 now with something like this:
public class ApiSecurityInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HandlerMethod method = (HandlerMethod) handler;
Api methodAnnotation = method.getMethodAnnotation(Api.class);
if (methodAnnotation != null) {
// this method is an #Api, we check the credentials
// you can do other things with annotation parameters at this point too
}
}
}
Then map it in servlet-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
...
<mvc:interceptors>
<bean class="com.orderpipe.prototype.server.web.interceptors.ApiSecurityInterceptor"/>
</mvc:interceptors>
Then in your actual controller:
#Controller
#RequestMapping(value = "/api-service")
public class AccountApiController {
#Api(type=CredentialType.OAUTH)
#RequestMapping(value="get", method = RequestMethod.GET)
public String get(Model model) {
// secured method via oauth, for example
// in a simpler example, you'd not have the parameter for credential type.
}
}
I use it to implement special servlet paths that implement different security mechanisms to the normal app, for example /api uses oAuth credentials.
I have the same need.
I consider an inconsistency that Spring MVC promotes the use of controller methods to handle requests, but the HandlerInterceptor interface does not supply the handler method that's going to handle the request as a parameter; only the controller object.
Requests are handled at the method level and it's the method execution what you need to intercept and for doing that efficiently you need to gain access to the method meta-information, for example, custom annotations declared at method level or its arguments.
The HandlerInterceptor.preHandle signature shoud be:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handlerInstance, Method handlerMethod)
throws Exception;
So that you can do something like this:
hadlerMethod.getAnnotation(MyCustomAnnotation.class);
GOT IT?
In my case, I wanted to implement indexed-paremeter mapping; something STRIPES FRAMEWORK has (or flash scoping).
Do I have to resort to AspectJ to implement my cross-cutting functionality? DISSAPOINTING!
Firstly this is against MVC architectural pattern. MVC architecture is an architectural pattern that desires to
isolate "domain logic" (the application logic for the user) from the user interface (input and presentation), permitting independent development, testing and maintenance of each (separation of concerns).
See here
And controller has a great work in it.It desires decoupling, focusing on design porpose, and etc. I hope software developers don't give up GRASP :/
Related
I have implemented IAuthenticationFilter to create a custom one. in the constructor I use structureMap to get instance of my IUnitOfWork. this authentication logic is to check user status in the database and ....
IUnitOfWork uow;
public CustomAuthenticatationAttribute()
{
this.uow = ObjectFactory.GetInstance<IUnitOfWork>();
}
I have configured structureMap to serve IUnitOfWork HttpContextScoped.
x.For<IUnitOfWork>().HttpContextScoped().Use(() => new MyDbContext());
but then something strange happened. I deleted the user in one action, but when the AuthenticationFilter is executed on another action, the instance of unitOfWork still returns the user ! I searched the web for hours and I come to this :
Are ActionFilterAttributes reused across threads? How does that work?
in short , it says that Filters are cached and used across requests !
Now I'm confused . how to deal with this ? shall I give up using unitOfWork and get back to using(var context = ....) ? or there is a correct way of using unitOfWork inside Filters .
I found a solution here
https://gist.github.com/ivanra/9019273
It replaces the DefaultFilterProvider and I prefer to avoid that if possible.
The solution you found with suppressing caching in the FilterProvider is actually the same solution that the MVC integration libraries for both Autofac and Simple Injector use.
But the caching behavior of attributes is just one of the many reasons why doing dependency injection in attributes is actually a bad idea.
The best solution is IMO to move to passive attributes if you can, or at least encapsulate the attributes logic and its dependencies into a component and don't do anything more than resolving and executing that component in the OnActionExecuting method. For instance:
public class CustomAuthenticatationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var action =
ObjectFactory.GetInstance<IActionFilter<CustomAuthenticatationAttribute>>();
action.OnActionExecuting(this, context);
}
}
What is the different between flash and model attribute?
I want to store an object and display it in my JSP as well as reuse it in other controller. I have use sessionAttribute and it works fine in the JSP, but the problem is when I try to retrieve that model attribute in other controller.
I lose some data. I searched around and found that flash attribute allows to past past value to different controller, doesn't it?
If we want to pass the attributes via redirect between two controllers, we cannot use request attributes (they will not survive the redirect), and we cannot use Spring's #SessionAttributes (because of the way Spring handles it), only an ordinary HttpSession can be used, which is not very convenient.
Flash attributes provide a way for one request to store attributes intended for use in another. This is most commonly needed when redirecting — for example, the Post/Redirect/Get pattern. Flash attributes are saved temporarily before the redirect (typically in the session) to be made available to the request after the redirect and removed immediately.
Spring MVC has two main abstractions in support of flash attributes. FlashMap is used to hold flash attributes while FlashMapManager is used to store, retrieve, and manage FlashMap instances.
Example
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model model) {
String some = (String) model.asMap().get("some");
// do the job
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttribute("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
In above example, request comes to handlePost, flashAttributes are added, and retrieved in handleGet method.
More info here and here.
I oftentimes want to return an Object as response body which is not supported by spring. So Instead I do:
public HttpEntity<?> doStuff() {
MyClass myObject = ... ;
return SomeHelper.toHttpEntity(myObject);
}
While this works, it is uncool, because it makes my code less testable and adds the same call over and over to various handler methods. Thus I wonder if I could add support for an additional type in spring.
I couldn't find anything on Google, but reading through the source code I found the interface HandlerMethodReturnValueHandler whose implementors do the conversion. So I'd implement that interface for my custom type, but how do I register it (using XML) in spring?
I don't think that you need your own HandlerMethodReturnValueHandler, but just in case:
<mvc:annotation-driven>
<mvc:return-value-handlers>
<bean class="my.own.Handler" />
</mvc:return-value-handlers>
If mvc is your default namepsace you omit the qualifier, of course.
In my ASP.NET Web API controller, I want to restrict access to those in the User role. The common way to do this is to extend the AuthorizeAttribute (example, example) and then sprinkle my controllers with my custom attribute (e.g. [AuthorizeUser]).
Another way to do this is to add a function in the controller's constructor. The constructor is required anyway because I'm using dependency injection.
Here's some code:
public class MyController: ApiController
{
private IUnitOfWork unitOfWork;
private IAccountUtils accountUtils;
// Constructor
public MyController(
IUnitOfWork unitOfWork,
IAccountUtils accountUtils)
{
this.unitOfWork = unitOfWork;
this.accountUtils = accountUtils;
// Restrict access to 'User' role
accountUtils.ThrowExceptionIfUserNotInRole(User.Identity, "User");
}
// More code
}
Because there are countless tutorial and examples of using a filter to authorize users I assumed that was the best way to go. However, when I stepped through my code in the debugger I found that the constructor method gets fired BEFORE the filter.
To optimize code, it makes sense to break as soon as possible if the user is not authorized to access the controller. If I'm not mistaken, then, it should be more efficient to perform authorization in the constructors instead of in a filter. Am I correct or am I missing something here?
It seems like your main concern is optimizing your code, and you're correct to note that the controller constructor runs before the authorization filter. But the difference in performance between those two solutions is extremely small and shouldn't really impact your service.
While throwing from a constructor might work, it's not the most elegant solution because it requires you to authorize in code rather than declaratively with an attribute. It also forces you to mix object instantiation logic with authorization logic which isn't as clean.
So I'd recommend just sticking to using an authorization filter for this one.
I'm attempting to create a generic controller, ie:
public class MyController<T> : Controller where T : SomeType
{ ... }
However, when I try to use it, I'm running into this error everywhere...
Controller name must end in 'Controller'
So, my question, Is it possible to make a generic controller in asp.net mvc?
Thanks!
If I understand you properly, what you are trying to do, is route all requests for a given Model through a generic controller of type T.
You would like the T to vary based on the Model requested.
You would like /Product/Index to trigger MyController<Product>.Index()
This can be accomplished by writing your own IControllerFactory and implementing the CreateController method like this:
public IController CreateController(RequestContext requestContext, string controllerName)
{
Type controllerType = Type.GetType("MyController")
.MakeGenericType(Type.GetType(controllerName));
return Activator.CreateInstance(controllerType) as IController;
}
Yes you can, it's fine and I've used them lots myself.
What you need to ensure is that when you inherit from MyController you still end the type name with controller:
public class FooController : MyController<Foo>
{
...
}
The default controller factory uses "convention" around controller names when it's trying to find a controller to dispatch the request to. You could override this lookup functionality if you wanted, which could then allow your generic controller to work.
This MSDN article...
http://msdn.microsoft.com/en-us/magazine/dd695917.aspx
... has a good writeup of what's going on.
This is a duplicate of asp.net mvc generic controller which actually contains the correct answer. Jeff Fritz's answer is absolutely not correct. Creating your own IControllerFactory will not get past the limitation in ExpressionHelper.GetRouteValuesFromExpression which is generating the error you are seeing. Implementing your own IControllerFactory will still leave you with errors whenever you call RedirectToAction, BuildUrlFromExpression, ActionLink, RenderAction, BeginForm, any any methods that call those.
What is interesting to me, is that Microsoft's "restriction by convention" is already enforced by the constraint "where TController : Controller" that is placed upon the type in the ExpressionHelper.GetRouteValuesFromExpression method. No generic will ever satisfy the convention validation:
string controllerName = typeof(TController).Name;
if (!controllerName.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)) {
throw new ArgumentException(MvcResources.ExpressionHelper_TargetMustEndInController, "action");
}
unless it is inherited by a class ending in "Controller" because typeof(AnyGeneric).Name will never end with "Controller".
If i was you, i'd get the MVC source and create a test MVC project with the source code so you can examine where the exception is generated and see what you can do about your generic idea and the enforced "*controller" naming convention.