ASP.NET MVC RequireHttps - asp.net-mvc

How do I use the ASP.NET MVC 2 Preview 2 Futures RequireHttps attribute?
I want to prevent unsecured HTTP requests from being sent to an action method. I want to automatically redirect to HTTPS.
MSDN:
RequireHttpsAttribute
RequireHttpsAttribute Members
RequireHttpsAttribute.HandleNonHttpsRequest Method
How do I use this feature?

I think you're going to need to roll your own ActionFilterAttribute for that.
public class RedirectHttps : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (!filterContext.HttpContext.Request.IsSecureConnection) {
filterContext.Result =
new RedirectResult(filterContext.HttpContext.Request.Url.
ToString().Replace("http:", "https:"));
filterContext.Result.ExecuteResult(filterContext);
}
base.OnActionExecuting(filterContext);
}
}
Then in your controller :
public class HomeController : Controller {
[RedirectHttps]
public ActionResult SecuredAction() {
return View();
}
}
You might want to read this as well.

My guess:
[RequireHttps] //apply to all actions in controller
public class SomeController
{
//... or ...
[RequireHttps] //apply to this action only
public ActionResult SomeAction()
{
}
}

Related

Asp.Net MVC How to log all actions being called

I need to be able to log all actions that are called from my asp.net mvc application. How and what would be the best way to achieve this? Where I log it to whether it be the console or log file doesn't matter.
You could create your own class which inherits from ActionFilterAttribute and then override the OnActionExecuting method.
Example
public class LogActionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.RequestContext.RouteData.Values["Controller"];
var action = filterContext.RequestContext.RouteData.Values["Action"];
//
// Perform logging here
//
base.OnActionExecuting(filterContext);
}
}
public class HomeController : Controller
{
[LogAction]
public ActionResult Index()
{
return View();
}
}
Hope this helps!
Credit HeyMega for their answer. Here's an example of an expanded implementation I arrived at in MVC5.
public class LogActionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var controller = filterContext.RequestContext.RouteData.Values.ContainsKey("Controller") ? filterContext.RequestContext.RouteData.Values["Controller"].ToString() : null;
var action = filterContext.RequestContext.RouteData.Values.ContainsKey("Action") ? filterContext.RequestContext.RouteData.Values["Action"].ToString() : null;
var area = filterContext.RequestContext.RouteData.DataTokens.ContainsKey("Area") ? filterContext.RequestContext.RouteData.DataTokens["Area"].ToString() : null;
var user = filterContext.RequestContext.HttpContext.User.Identity.GetUserId();
Task.Run(() => Generic().AreaActionLog(user, area, controller, action));
base.OnActionExecuting(filterContext);
}
}
I chose to separate the method doing the actual logging into a separate process, if anything goes wrong with the Database interaction, or the DB interaction takes several seconds, the UI is uninterrupted.
You can then decorate the entire controller with [LogAction] attribute like so.
[LogAction]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult Contact()
{
return View();
}
}
Or selectively apply the attribute by decorating individual methods:
public class HomeController : Controller
{
[LogAction]
public ActionResult Index_Logs_Things()
{
return View();
}
}
Hope this helps someone.
You could try Audit.NET library with its Audit.MVC and the different data providers to store the logs on files, eventlog, sql, redis, mongo, and much more.
With the MVC extension you just need to decorate your controllers or actions with an attribute:
[Audit]
public class HomeController : Controller
{ ... }
Execute a static configuration to set the output of your logs:
Audit.Core.Configuration.Setup()
.UseFileLogProvider(_ => _
.Directory(#"C:\Logs"));
And it will provide the infrastructure to log the interactions with your MVC application.

Authorize a parameter for an action in MVC5

I commonly need to authorize a particular parameter to be evaluated in a service call within an action in MVC5. For instance, let's say that my action is public ActionResult Edit(string partnerName).
Today, I handle this by always evaluating if (!User.CanAccessPartnerModule(THIS_MODULE_ID, partnerName)) throw new UnauthorizedException();
However, I would like to be able to do something like this:
[Authorize(Roles = THIS_MODULE_ID)]
public ActionResult Edit([AuthorizePartnerModule(THIS_MODULE_ID)] string partnerName)
{
...
}
To be clear, 1) I don't think the AuthorizeAttribute would be necessary if this were implemented as I envision, and 2) the thing that doesn't exist is the AuthorizePartnerModuleAttribute.
Is there a ready-made attribute or tutorial that explains how this may be accomplished? And if not, is this not advisable to do?
You could extend authorization with a custom authorization filter by creating a subclass of AuthorizeAttribute
using System.Web;
using System.Web.Mvc;
namespace Filters
{
public class AuthorizePartnerModule : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
// getting the parameter from the request
string partnerName = httpContext.Request.Params["groupId"].ToString();
// custom validation
return User.CanAccessPartnerModule(THIS_MODULE_ID, partnerName);
}
}
}
And then, you could validate your action method with:
[AuthorizePartnerModule(Roles = THIS_MODULE_ID)]
public ActionResult Edit(string partnerName)
{
...
}
Another option would be to create a custom ActionFilter (an implementation of IActionFilter). An ActionFilter implements two methods:
OnActionExecuting is executed right before the action method
OnActionExecuted is executed right after the action method execution.
So, you could make the necessary validation with something like:
using System.Web.Mvc;
namespace Filters {
public class AuthorizePartnerModule : FilterAttribute, IActionFilter
{
public void OnActionExecuting(ActionExecutingContext filterContext)
{
// getting the parameter from the request
string partnerName = filterContext.ActionParameters["partnerName"].ToString();
// custom validation
if (!User.CanAccessPartnerModule(THIS_MODULE_ID, partnerName))
{
filterContext.Result = new HttpNotFoundResult();
}
}
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// do nothing
}
}
}
In this case, however ,you would have to validate like that:
[Authorize(Roles = THIS_MODULE_ID)]
[AuthorizePartnerModule]
public ActionResult Edit(string partnerName)
{
...
}

MVC Set accessibility level on a method called from ajax

I would like to protect my public method from being called by a user.
Because I'm calling the action from an ajax script I can't use any access modifiers, (private, protected etc).
Also, [HttpPost] doesn't stop the user from doing a fake request.
Anyone got a solution?
Thanks
Create an action filter that allows action methods to be called by AJAX only
namespace MyFilters
{
[AttributeUsage(AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 404;
filterContext.Result = new HttpNotFoundResult();
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
}
Then apply this to the action method
[AjaxOnly]
public JsonResult DoSomething()
{
....

Query related to [OutputCache] attribute

In order to disable browser cache, to reliably instructing the browser not to cache, I found the best solution was to create your own [NoCache] attribute class
public class NoCacheSettingsAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}
And a global filter settings
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// Makes sure that cached pages are not served to any browser including chrome
filters.Add(new NoCacheSettingsAttribute());
}
I want to use [OutputCache(CacheProfile = "2Hour")] in some ActionResult of a controller and also want to use NoCacheSetting for rest of controller globally , Let say in BaseController, (all controller inherit from BaseController)
So the question is that will it work properly ? Or I have to put rest of controller 1 by one ?
Why not simply exclude controller actions already decorated with the OutputCache attribute from processing:
public class NoCacheSettingsAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
var descriptor = new ReflectedControllerDescriptor(
filterContext.Controller.GetType()
);
var action = descriptor.FindAction(
filterContext.Controller.ControllerContext,
filterContext.RequestContext.RouteData.GetRequiredString("action")
);
if (!action.GetCustomAttributes(typeof(OutputCacheAttribute), true).Any())
{
// The controller action is not decorated with the
// [OutputCache] attribute, so you could apply your NoCache logic here
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
}
}
}

Is there any attribute relating to AJAX to be set for ASP.NET MVC controller actions?

I want to use partial views with AJAX calls in ASP.NET MVC, and this is the first time I'm using it. I just searched to see if there is anything special I should know beforehand, and one of'em that I'm curious about, is to see if there is any special attribute that should be set or is related to AJAX calls? Something like [ChildActionOnly] or [HttpGet]
I don't think there is built in attribute for ajax, but you can create your own AjaxOnly filter like this:
public class AjaxOnlyAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return controllerContext.RequestContext.HttpContext.Request.IsAjaxRequest();
}
}
And decorate your action methods like this:
[AjaxOnly]
public ActionResult AjaxMethod()
{
}
See Also: ASP.NET MVC Action Filter – Ajax Only Attribute for another way of implementing this
ASP.NET MVC provides an extension method to check if an Request is an Ajax Request. You can use it to decide if you want to return a partial view or json result instead of a normal view.
if (Request.IsAjaxRequest())
{
return PartialView("name");
}
return View();
To limit an action method to Ajax calls only you can write a custom attribute. In case of a normal request this filter will return a 404 not found http exception.
[AttributeUsage(AttributeTargets.Method)]
public class AjaxOnlyAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 404;
filterContext.Result = new HttpNotFoundResult();
}
else
{
base.OnActionExecuting(filterContext);
}
}
}
you can use it like that:
[AjaxOnly]
public ActionResult Index() {
// do something awesome
}
A spinoff of Muhammad's answer letting you specify that it mustn't be an ajax request as well:
using System.Web.Mvc;
public class AjaxAttribute : ActionMethodSelectorAttribute
{
public bool ajax { get; set; }
public AjaxAttribute() { ajax = true; }
public AjaxAttribute(bool a) { ajax = a; }
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return ajax == controllerContext.HttpContext.Request.IsAjaxRequest();
}
}
This lets you do things like...
[Ajax]
public PartialViewResult AjaxUpdatingPage() {
return PartialView();
}
[Ajax(false)]
public ViewResult NotAjaxUpdatingPage() {
return View();
}
Update for ASP.NET Core:
You will need to replace the usings and method signature/body with the following...
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
using Microsoft.AspNetCore.Routing;
using System.Linq;
public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor action)
{
// Using ASP.NET 6 strongly typed header:
return ajax == routeContext.HttpContext.Request.Headers.XRequestedWith.Contains("XMLHttpRequest");
// Older versions:
return ajax == routeContext.HttpContext.Request.Headers.Any(h => h.Key == "X-Requested-With" && h.Value.Contains("XMLHttpRequest"));
}
There is an [AjaxOnly] attribute provided in the ASP.NET MVC 3 Futures collection. It's a part of the official ASP.NET MVC Codeplex site that provides features before they are officially included in a future version of ASP.NET MVC.
You can download it here. To use it, add a reference to the Microsoft.Web.Mvc assembly included in the release package.
There is an explanation of the attribute on this page, along with all the other great features you can use.
For those looking for a .NET Core solution it's a little bit more involved, as IsAjaxRequest() is no longer available.
Below is the code I've used in production on several projects to great effect.
public class AjaxOnlyAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(RouteContext routeContext, ActionDescriptor actionDescriptor)
{
if(routeContext.HttpContext.Request.Headers != null &&
routeContext.HttpContext.Request.Headers.ContainsKey("X-Requested-With") &&
routeContext.HttpContext.Request.Headers.TryGetValue("X-Requested-With", out StringValues requestedWithHeader))
{
if(requestedWithHeader.Contains("XMLHttpRequest"))
{
return true;
}
}
return false;
}
}
my solution follows the [ChildActionOnly] implementation:
public class AjaxOnlyAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (!filterContext.HttpContext.Request.IsAjaxRequest())
throw new InvalidOperationException(string.Format(
CultureInfo.CurrentCulture,
"The action '{0}' is accessible only by an ajax request.",
filterContext.ActionDescriptor.ActionName
));
}
}

Resources