可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have two actions inside my controller (shoppingCartController)
public ActionResult Index()
{
//some stuff here
return View(viewModel);
}
public ActionResult AddToCart(int id)
{
return RedirectToAction("Index");
}
Is there anyway to prevent the users from directly calling the index action by typing the url in the browser?
For example: If the user browses to shoppingCart/index
be redirected to Home/Index.
回答1:
You could use the [ChildActionOnly]
attribute on your action method to make sure it's not called directly, or use the ControllerContext.IsChildAction
property inside your action to determine if you want to redirect.
For example:
public ActionResult Index()
{
if(!ControllerContext.IsChildAction)
{
//perform redirect here
}
//some stuff here
return View(viewModel);
}
If you can't make the Index action a child action, you could always check the referrer, understanding that it's not foolproof and can be spoofed. See:
How do I get the referrer URL in an ASP.NET MVC action?
回答2:
Try making this Index controller action as private
. A method with private
access modifier should not be accessible from outside class.
And then, rahter than calling RedirectToAction
from AddToCart call it as simple method like below:
private ActionResult Index()
{
//some stuff here
return View(viewModel);
}
public ActionResult AddToCart(int id)
{
return Index();
}
回答3:
If all you are worried about is the user typing in the URL, then using the HttpPost attribute should prevent your action from being called that way:-
[HttpPost]
public ActionResult AddToCart(int id)
{
This prevents GET requests from calling that action. It doesn't however stop someone writing a dummy form and POSTing to your action.
If you are worried about something a little more malicious, you might want to implement some form of anti-forgery token, there's some good info on that here.
EDIT
OK, so on re-reading the question the above doesn't quite address your issue.
How about a route? if you had something like the below, it would prevent ShoppingCart/Index being called and redirect the user to your site index.
routes.MapRoute(
"ShoppingCartIndex",
"ShoppingCart/Index",
new { controller = "Home", action = "Index" }
);
回答4:
If SessionState is enabled, you can use controller's TempData to achieve your goal. Set TempData in AddToCart action, and only display Index view if Index action can get TempData key set in AddToCart action.
If you need this for multiple actions/projects, use combination of custom Action Filter and ActionResult. Like this:
// Controller
[PreventDirectAccess]
public ActionResult Index()
{
//some stuff here
return View(viewModel);
}
public ActionResult AddToCart(int id)
{
return new PreventDirectAccessRedirectToRouteResult(new RouteValueDictionary
{
{"action", "Index"}
});
}
// Filter
public class PreventDirectAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (filterContext.Controller.TempData[PreventDirectAccessRedirectToRouteResult.Executed] == null)
filterContext.Result = new HttpNotFoundResult();
base.OnActionExecuting(filterContext);
}
}
// ActionResult
public class PreventDirectAccessRedirectToRouteResult : RedirectToRouteResult
{
public const string Executed = "PreventDirectAccessRedirectExecuted";
public override void ExecuteResult(ControllerContext context)
{
context.Controller.TempData[Executed] = true;
base.ExecuteResult(context);
}
}
回答5:
Here is written code how to prevent browser direct access to action method:
Write below code in FilterConfig.cs
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class NoDirectAccessAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.UrlReferrer == null ||
filterContext.HttpContext.Request.Url.Host != filterContext.HttpContext.Request.UrlReferrer.Host)
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Home", action = "Index", area = "" }));
}
}
}
Now apply this code on your action method
[NoDirectAccess]
public ActionResult MyActionMethod()
This will restrict to call directly any class or action method.
回答6:
NonAction is the attribute to use. It is part of the MVC library, so you don't have to create your own attribute.
回答7:
This is untested, but I believe you can use the Validate Anti Forgery Token
In your code on the page, you will need to place an validation token in the form that is to be posted:
@Html.AntiForgeryToken()
Which produces:
<input name="__RequestVerificationToken" type="hidden" value="s9+jDREFMlNPkAT2zOlmhJZQbbDOzMhuarSTG1BVAC4GeHiNL5VtuQo7CQTF8obw8hEYIQac9YaQh+qVcF0xj0eNO7lVdezz+JxuSKGQo2d2gEdtkEdR+XTTFas4Gh6fjSYc7A1rWF8AAhxjZ9j6GlbRhECZOPAlPAItnjz49QQ=" />
This token is automatically picked up by any action that has this attribute:
[ValidateAuthenticationToken]
public ActionResult AddToCart(int id)
{
return Index();
}
If the request is direct then an error will occur.