2012-02-23 13 views
10

Ho due azioni all'interno mio controller (shoppingCartController)Asp.net mvc Come impedire al browser di chiamare un metodo di azione?

public ActionResult Index() 
    { 
     //some stuff here 
     return View(viewModel); 
    } 


    public ActionResult AddToCart(int id) 
    { 

     return RedirectToAction("Index"); 

    } 

Esiste un modo per evitare che gli utenti di chiamare direttamente l'azione index digitando l'URL nel browser?

Ad esempio: se l'utente accede a shoppingCart/index essere reindirizzato a Home/Index.

risposta

13

è possibile utilizzare l'attributo [ChildActionOnly] sul metodo di azione per assicurarsi che non è chiamato direttamente, o utilizzare il ControllerContext.IsChildAction proprietà all'interno dell'azione per determinare se si desidera reindirizzare.

Ad esempio:

public ActionResult Index() 
{ 
    if(!ControllerContext.IsChildAction) 
    { 
     //perform redirect here 
    } 

    //some stuff here 
    return View(viewModel); 
} 

Se non è possibile rendere l'azione Index un'azione bambino, si può sempre controllare il referrer, comprendendo che non è infallibile e può essere falsificato. Vedi:

How do I get the referrer URL in an ASP.NET MVC action?

+0

se metto [ChildActionOnly] sul mio metodo index, non verrà chiamato da redirectToAction. funziona solo se ho html.action(). anche controllerContext.ischildAction non riconosce il redirecttoaction come chiamata childaction. – 1AmirJalali

+0

Se vuoi un'azione che funzioni come un'azione regolare (cioè puoi RedirectToAction ad esso) ma puoi reindirizzare da un posto solo, puoi provare a controllare il referer all'interno dell'azione, reindirizzarti a home/index se il referer non è è l'url AddToCart. Ciò non sarebbe infallibile, tuttavia, poiché il referente può essere falsificato. –

+0

stavo per controllare la risposta StatusCode. come dovrei controllare il referere? – 1AmirJalali

3

Provare a effettuare questa azione del controller indice come private. Un metodo con il modificatore di accesso private non dovrebbe essere accessibile dalla classe esterna.

E poi, rahter che chiamare RedirectToAction da addToCart chiamano metodo tanto semplice come di seguito:

private ActionResult Index() 
{ 
    //some stuff here 
    return View(viewModel); 
} 


public ActionResult AddToCart(int id) 
{ 

    return Index(); 

} 
+0

ma non reindirizza gli utenti a casa/indice. – 1AmirJalali

+0

quindi non risolve il problema di reindirizzare l'utente se ha inserito esplicitamente l'url shoppingCart/Index ha appena dato l'errore che le risorse non possono essere trovate – 1AmirJalali

+0

Ok. Quello che hai in Index dovrebbe essere un metodo di supporto che dovrebbe essere chiamato da AddToCart. Il metodo dell'Indice effettivo dovrebbe essere pubblico e reindirizzare a Home/Index. – Maheep

2

Se tutto siete preoccupati è l'utente che digita l'URL, quindi utilizzando l'attributo HttpPost dovrebbe impedire l'azione di essere chiamato in questo modo: -

[HttpPost] 
public ActionResult AddToCart(int id) 
{ 

questo modo si evita OTTIENI richieste di chiamare quell'azione. Tuttavia, non impedisce a qualcuno di scrivere un modulo fittizio e di inviare POST alla tua azione.

Se sei preoccupato per qualcosa di un po 'più malevolo, potresti voler implementare qualche forma di token anti-contraffazione, ci sono alcune buone informazioni su quello here.

EDIT

OK, così via rileggendo la questione di cui sopra non abbastanza affrontare il problema.

Come su un percorso? se avessi qualcosa di simile a quanto riportato di seguito, impedirebbe a ShoppingCart/Index di essere chiamato e reindirizzare l'utente all'indice del tuo sito.

 routes.MapRoute(
      "ShoppingCartIndex", 
      "ShoppingCart/Index", 
      new { controller = "Home", action = "Index" } 
     ); 
+0

Non penso che sia l'azione AddToCart che desidera proteggere, è l'azione Index, che è un GET. –

+1

Ma hai ragione, l'azione AddToCart ha sicuramente bisogno di essere un POST. :-) –

+0

no im preoccupato per la digitazione di esempio example.com/shoppingcart e vedere il carrello degli acquisti vuoto. – 1AmirJalali

0

Questo non è testato, ma credo che è possibile utilizzare la Convalida Anti Contraffazione Moneta

Nel codice della pagina, è necessario inserire un token di convalida nella forma che deve essere pubblicato:

@Html.AntiForgeryToken() 

che produce:

<input name="__RequestVerificationToken" type="hidden" value="s9+jDREFMlNPkAT2zOlmhJZQbbDOzMhuarSTG1BVAC4GeHiNL5VtuQo7CQTF8obw8hEYIQac9YaQh+qVcF0xj0eNO7lVdezz+JxuSKGQo2d2gEdtkEdR+XTTFas4Gh6fjSYc7A1rWF8AAhxjZ9j6GlbRhECZOPAlPAItnjz49QQ=" /> 

Questo token viene prelevato automaticamente da qualsiasi azione che ha questo attributo:

[ValidateAuthenticationToken] 
public ActionResult AddToCart(int id) 
{ 
    return Index(); 
} 

Se la richiesta è diretta, si verificherà un errore.

+0

Mi piace questa idea ma cosa succede se questo link I non è in una forma? – retslig

+1

@retslig - Se intendi una richiesta GET standard, [non puoi utilizzare questo metodo] (http://stackoverflow.com/a/4943610/59532) – Dann

1

Se SessionState è abilitato, è possibile utilizzare il controller TempData per raggiungere il proprio obiettivo. Imposta TempData nell'azione AddToCart e visualizza solo la vista Indice se l'azione Indice può ottenere la chiave TempData impostata nell'azione AddToCart.

Se è necessario per più azioni/progetti, utilizzare la combinazione di Filtro azione personalizzato e ActionResult. Come questo: codice

// 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); 
    } 
} 
0

Qui è scritto come impedire l'accesso diretto del browser al metodo di azione: Scrivi sotto il codice a 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 = "" })); 
     } 
    } 
} 

Ora applicare questo codice sul tuo metodo di azione

[NoDirectAccess] 
public ActionResult MyActionMethod() 

Ciò limiterà a chiamare direttamente qualsiasi classe o metodo di azione.

0

NonAction è l'attributo da utilizzare. Fa parte della libreria MVC, quindi non devi creare il tuo attributo.

Problemi correlati