Is it possible to block any other use of json result and allow just requests from my application ?
when we use something like this:
Json(q, JsonRequestBehavior.AllowGet)
it allow all requests from anywhere.is there any authentication exist to check where request is from ?
I think you mean:
How to allow only AJAX requests?
If so, view the following blog post. It describes creating a reusable filter:
AjaxOnly attribute
The code seems quite simple, but I haven't used it myself:
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if(!filterContext.HttpContext.Request.IsAjaxRequest())
filterContext.HttpContext.Response.Redirect("/error/404");
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
That you can then apply to controllers and actions:
[AjaxOnly]
public ActionResult AjaxActionMethod()
{
//....
}
The filter code presumes the existence of an action on some controller that can be reached by the following route:
/error/404
As a result, I have amended the code, and produced an easy way of adding an arbitrary error route (with a default value of "/error/404"):
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public AjaxOnlyAttribute(){}
public AjaxOnlyAttribute(string ErrorRoute)
{
this.ErrorRoute = ErrorRoute;
}
string errorRoute = "/Error/404"; // default route
public string ErrorRoute
{
get { return errorRoute; }
set { errorRoute = value; }
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
filterContext.HttpContext.Response.Redirect(this.ErrorRoute); //
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
This can now be used as follows:
[AjaxOnly(ErrorRoute = "/MyArbitraryRoute/MyArbitraryParameter")
public ActionResult AjaxActionMethod()
{
//....
}
Add the [Authorize] attribute to your methods or controllers that you want to protect. You can specify the group membership and a login will be required.
If you only want a method to be callable by your own application, change the method declaration from public to internal. This will limit the scope of the method to calls from within your application.
Related
I wish to create an object per http request within an ActionFilter and pass this object to the controller. So far I have tried Request.Properties[] like the following
public class DbReadonlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
actionContext.Request.Properties["CustomObjectKey"] = new MyClass();
And I have also tried to assign the new object direct to a ControllerBase class.
public class DbReadonlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var controller = (MyControllerBase) actionContext.ControllerContext.Controller;
controller.StorageContextFactory = new MyClass();
The problem is that neither technique delivers an instance of MyClass to the controller because the new Property["CustomObjectKey"] is lost in the Webapi pipeline by the time a controller method is invoked.
The controller is re-instantiated by the webapi pipeline after the call to action filter OnActionExecuting().
Break points confirm the Webapi pipeline schedules the following event flow during a single http request.
constructor MyControllerBase()
MyAuthenticationFilter
Filter OnActionExecuting()
constructor MyControllerBase()
MyController.MethodA()
The double instantiation of MyControler is odd, but right now I am looking for any technique to pass a newly created object from an action filter to a controller.
Edit-1: The MyAuthorizationFilter mentioned in v1 of this question is actually an Authentication filter. Still investigating.
Solution: The bug was in another filter. After I removed my authentication filter the problem reported in this question went away.
You will have to use .add method Request.Properties collection.
public class DbReadonlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
actionContext.Request.Properties.Add(new KeyValuePair<string, object>("CustomObjectKey", new MyClass()));
You can retrieve this value from your api controller.
object _customObject= null;
if (Request.Properties.TryGetValue("CustomObjectKey", out _customObjectKey))
{
MyClass myObject = (MyClass)_customObject;
}
Another way to pass variable from ActionFilter.OnActionExecuting() to an ApiController:
public class CustomFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
actionContext.ControllerContext.RequestContext.RouteData.Values["CustomValue"] = "CustomValue";
}
}
Pay attention to use ActionFilterAttribute for Web API :
System.Web.Http.Filters.ActionFilterAttribute
Not for MVC classic :
System.Web.Mvc.ActionFilterAttribute
Using:
[CustomFilter]
public class SomeController : ApiController
{
string customValue = RequestContext.RouteData.Values.ToDictionary(x => x.Key, y => y.Value)["user_id"].ToString();
//...
}
I'm following a book called 'Asp.Net MVC4 in Action'. And now at certain point they say, Instead of relying on if statement within our code to check if the request is Ajax or not, we could use an action method selector to differentiate it. And what they have done is create a class AcceptAjaxAttribute with following code
using System;
using System.Reflection;
using System.Web.Mvc;
namespace CustomAjax
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AcceptAjaxAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.IsAjaxRequest();
}
}
}
and the function in controller which looked like this before
var speaker = _repository.FindSpeaker(id);
if(Request.IsAjaxRequest())
{
return Json(speaker, JsonRequestBehaviour.AllowGet);
}
return View();
has changed to something like this
[AcceptAjax]
public ActionResult Details(int id)
{
var speaker = _repository.FindId(id);
return Json(speaker, JsonRequestBehavior.AllowGet);
}
[ActionName("Details")]
public ActionResult Details_NonAjax(int id)
{
var speaker = _repository.FindId(id);
return View();
}
To be honest I have no idea what is being done or why we created new class and used that[AcceptAjax] thingy. Can someone may be explain it to me.
Before you had one action with an if inside, after the refactoring you have 2 actions each returning a different type of result. The ActionMethodSelectorAttribute is used to select the proper action based on some condition. Since the 2 actions have the same name (Details), ASP.NET MVC will use this attribute to select the one or the other based on whether an AJAX request is being used.
But honestly I don't like this approach at all. You now have 2 actions and have repeated the var speaker = _repository.FindId(id); call twice which is not very DRY. Wouldn't it be better if you had this?
[AcceptAjax]
public ActionResult Details(int id)
{
var speaker = _repository.FindId(id);
return View(speaker);
}
If you are like me and think that this is better, then simply replace this AcceptAjaxAttribute you got from the book with an action filter:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AcceptAjaxAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
{
var result = filterContext.Result as ViewResultBase;
if (result != null && result.Model != null)
{
filterContext.Result = new JsonResult
{
Data = result.Model,
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
}
}
The OnActionExecuted method will be invoked after the controller action has finished running and returned some result. Inside this method we verify whether the controller action returned a ViewResultBase (ViewResult or PartialViewResult) and whether a model has been passed. If this is the case we simply replace this result by a JsonResult.
And if you want to avoid decorating all your controller actions with this [AcceptAjax] attribute, you could register it as a global action filter in your ~/App_Start/FilterConfig.cs:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AcceptAjaxAttribute());
}
}
I have a base request type..
class RequestBase
{
public string inputId;
public string derivedid;
}
and types that inherit ..
class RequestA : RequestBase
{
public string name;
}
and
class RequestB : RequestBase
{
public string color;
}
I have a webapi service, some actions take an input parameter of RequestA, some take RequestB
[HttpPost]
[MyFilter]
[ActionName("Process1")]
public HttpResponseMessage Process1(RequestA request)
{
//do something with request.derivedId
}
[HttpPost]
[MyFilter]
[ActionName("Process2")]
public HttpResponseMessage Process2(RequestB request)
{
//do something with request.derivedId
}
I have an actionfilter that takes the inputId from the request and generates a derivedId
public override void OnActionExecuting(HttpActionContext actionContext)
{
RequestBase request = (RequestBase)actionContext.ActionArguments["request"];
string inputId = request.inputId;
string derivedId = inputId + "123";
// ?? somehow inject derivedId back into the actionContext so that my controller methods can access?
}
As my comment states above, I'd like to populate the derivedId field and have it accessible to my controller methods.
Thanks in advance
There's a few solutions to this problem already described in this thread - one of them should suit you:
ASP.NET MVC Pass object from Custom Action Filter to Action
I am writing an MVC 3 app where users will be able to log in and manage their data. I want to prevent users from viewing or tampering with other user's data. My first instinct was to just verify access to the relevant object in each action method like this:
public ActionResult ShowDetails(int objectId)
{
DetailObject detail = _repo.GetById(objectId);
if (detail.User.UserID != (Guid)Membership.GetUser().ProviderUserKey)
{
return RedirectToAction("LogOff", "Account");
}
}
This works fine, but I thought it might be better to put the object authorization code into a custom Authorize attribute derived from AuthorizeAttribute, which I could then apply to the controller. Unfortunately, I have not been able to find a way to access the action method parameters from within my custom Authorize attribute. Instead, the only way I have found to access the incoming objectId is by examining httpContext.Request or filterContext.RequestContext.RouteData.Values:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private int _objectId = 0;
private IUnitOfWork _unitOfWork;
public MyAuthorizeAttribute(IUnitOfWork uow)
{
_unitOfWork = uow;
}
public override void OnAuthorization(AuthorizationContext filterContext)
{
int.TryParse((string) filterContext.RequestContext.RouteData.Values["id"], out _objectId);
base.OnAuthorization(filterContext);
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
int objectId = 0;
if (httpContext.Request.Params.AllKeys.Contains("id", StringComparer.InvariantCultureIgnoreCase))
{
int.TryParse(httpContext.Request[idKey], out objectId);
}
if (objectId != 0)
{
if (!IsAuthorized(objectId, httpContext.User.Identity.Name))
{
return false;
}
}
if (_objectId != 0)
{
if (!IsAuthorized(objectId, httpContext.User.Identity.Name))
{
return false;
}
}
return base.AuthorizeCore(httpContext);
}
private bool IsAuthorized(int objectId, string userName)
{
DetailObject detail;
detail = _unitOfWork.ObjectRepository.GetById(objectId);
if (detail == null)
{
return false;
}
if (userName != detail.User.UserName)
{
return false;
}
return true;
}
}
I find this approach to be very clunky. I really don't want to have to poke around in the RouteData or Request objects; it would be much cleaner to be able to access the action method parameters since model binding would have already pulled out the relevant data from the RouteData and Request.
I know I can access action method parameters from a custom Action Filter (as detailed here), but shouldn't data authorization code be placed in an Authorize Filter? The more examples I see of Authorize filters, the more I get the impression that they are intended only to handle roles.
My main question is: How do I access action method parameters from my custom Authorize Attribute?
Answer to your main question: no, unfortunately AuthorizationContext does not provide access to action parameters.
First off, you could use ValueProvider to not have to deal with whether the id is part of the route or a query parameter or HTTP posted, as follows:
public override void OnAuthorization(AuthorizationContext filterContext)
{
string id = filterContext.Controller.ValueProvider.GetValue("id").AttemptedValue;
...
}
This works for simple data types and introduces little overhead. However once you start using custom model binders for your action parameters, you have to inherit your filter from ActionFilterAttribute to avoid double binding:
[MyFilter]
public ActionResult MyAction([ModelBinder(typeof(MyModelBinder))] MyModel model)
{
...
}
public class MyFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var model = filterContext.ActionParameters["model"] as MyModel;
...
}
}
While semantically inheriting from AuthorizeAttribute for authorization purposes sounds better, there are no other reasons for doing this. Moreover, I find using ActionFilterAttribute easier, as all you have to do is override only one method, not keeping a state for subsequent methods.
I have defined a custom authorization attribute. In order to avoid listing the attribute above every ActionResult in my Controller(s), I’ve added the attribute to my global.asax as follows:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new MyAuthorizeAttribute());
}
An unintended consequence of this, however, is that my authorization code is getting called during all of my JsonResult calls as well. Is there a way for MyAuthorizeAttribute to get invoked ONLY on ActionResult calls and NOT on JsonResult calls? I'm using MVC3.
Does the filter run before or after the action method?
If it runs before, you can't know what concrete type will be returned, because all actions return ActionResult (unless you specifically return JsonResult - that's another story).
If it runs after the action method, then in your filter code check whether the result is a JsonResult, like that:
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
if (!(filterContext.Result is JsonResult))
{
// do whatever you want...
}
base.OnResultExecuting(filterContext);
}
I disagree with the previous answer. You seem to have approached this from the wrong end. You should be looking at the request type, not the return type.
You can check for Ajax requests before the action in your filter. You should have something like this...
public class MyAuthorizeAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
return;
// else do authorisation stuff...
}
}