2012-04-30 25 views
7

Sto provando a dare un'occhiata a tutti gli attributi di autenticazione che possono decorare i metodi di azione nei miei controller in un'applicazione MVC 3. Lo sto facendo con i miei metodi di estensione HtmlHelper che sono fondamentalmente wrapper di ActionLink (per darti il ​​contesto di quali informazioni sono disponibili al runtime). Ho una soluzione di base, ma i metodi sovraccaricati lo hanno appena fatto esplodere. So che il framework sta risolvendo internamente gli url ai metodi di azione, ma dopo aver guardato attraverso il codice per System.Web.Mvc.LinkExtensions, non ho ancora trovato esattamente come sta accadendo, quindi sono un po 'bloccato su come per affrontare questo problema.Come recuperare gli attributi del metodo di azione richiesto

Ecco il codice che ho finora per risolvere il metodo in questione:

private static bool _IsUserAuthorized(HtmlHelper html, 
    string controllerName, string actionName) 
{ 
    controllerName = controllerName ?? 
    html.ViewContext.RouteData.GetRequiredString("controller"); 

    var factory = ControllerBuilder.Current.GetControllerFactory(); 
    var controller = factory.CreateController(
    html.ViewContext.RequestContext, controllerName); 

    Type controllerType = controller.GetType(); 
    var methodInfo = controllerType.GetMethod(actionName, 
    BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); 

    ... check authentication 
} 

Quindi il mio problema attuale è che quando un metodo viene sovrascritto, ottengo "incontro ambiguo trovato" eccezioni. Sto indovinando che ho bisogno di elaborare il RouteValues ​​per risolvere eventuali parametri del metodo in modo da poter identificare in modo univoco quello giusto. Qualcuno ha alcuni suggerimenti su come farlo? In alternativa, il framework fornisce già un mezzo per risolvere il metodo esatto necessario?

Grazie mille!

+0

OK, così ho continuato a scavare nel codice sorgente MVC3 e sembra che ho bisogno di ottenere un'istanza ControllerDescriptor e l'uso per ottenere un ActionDescriptor per il metodo di azione appropriato. Quindi, se questo è il caso, come faccio a ottenere ControllerContext del controller appropriato quando il metodo di azione richiesto non è il controller in HtmlHelper.ViewContext.Controller? –

+0

Ottenere un ControllerContext risulta essere piuttosto semplice. Ottenere un ControllerDescriptor, non così tanto. qualche idea? –

+0

Codice trovato [qui] (http://weblogs.asp.net/jeffreyzhao/archive/2009/01/30/extend-asp-net-mvc-for-asynchronous-action.aspx) per ottenere ControllerDescriptor e ActionDescriptor. Avvicinarsi ... –

risposta

2

MODIFICA: aggiornato il metodo per includere informazioni da this page. Questa versione finale esamina gli AuthorizationFilters per il metodo di azione richiesto e verifica se l'utente è autorizzato a eseguire l'azione.

Così ho cercato su System.Web.Mvc.ControllerActionInvoker e ho trovato i metodi e i costruttori necessari. ControllerDescriptor.FindAction() ha finito per essere la chiave. Qui di seguito, ho copiato il metodo che ho scritto che si recuperare tutti gli attributi

private static bool _IsUserAuthorized(HtmlHelper htmlHelper, 
    string controllerName, string actionName) 
{ 
    ControllerContext controllerContext = null; 
    //if controllerName is null or empty, we'll use the 
    // current controller in HtmlHelper.ViewContext. 
    if (string.IsNullOrEmpty(controllerName)) 
    { 
    controllerContext = htmlHelper.ViewContext.Controller.ControllerContext; 
    } 
    else //use the controller factory to get the requested controller 
    { 
    var factory = ControllerBuilder.Current.GetControllerFactory(); 
    ControllerBase controller = (ControllerBase)factory.CreateController(
     htmlHelper.ViewContext.RequestContext, controllerName); 
    controllerContext = new ControllerContext(
     htmlHelper.ViewContext.RequestContext, controller); 
    } 

    Type controllerType = controllerContext.Controller.GetType(); 
    ControllerDescriptor controllerDescriptor = new ReflectedControllerDescriptor(controllerType); 
    ActionDescriptor actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName); 
    if (actionDescriptor == null) 
    return false; 

    FilterInfo filters = new FilterInfo(FilterProviders.Providers.GetFilters(
    controllerContext, actionDescriptor)); 

    AuthorizationContext authContext = new AuthorizationContext(controllerContext, actionDescriptor); 
    foreach (IAuthorizationFilter authFilter in filters.AuthorizationFilters) 
    { 
    authFilter.OnAuthorization(authContext); 
    if (authContext.Result != null) 
     return false; 
    } 
    return true; 
} 
0

Il modo normale per aggiungere il codice di autorizzazione è utilizzare un Authorization Filter.

IAuthorizationFilter.OnAuthorization fornisce un oggetto AuthorizationContext che ha una proprietà ActionDescriptor.

+0

Stiamo già usando i filtri di autorizzazione, ma a meno che non mi manchi, il framework non ti fornisce un mezzo per ispezionare quell'autorizzazione prima di invocare un'azione. Sto cercando di nascondere i collegamenti dagli utenti che non hanno accesso per eseguire le azioni a cui è collegato, quindi ho bisogno di ispezionare gli attributi di autorizzazione prima di visualizzare html. Gestire OnAuthorization sarà troppo tardi nella catena per la funzionalità di cui ho bisogno. –

Problemi correlati