2011-04-06 26 views
10

Ho una classe di autorizzazione personalizzata che eredita da FilterAttribute e implementa IAuthorizationFilter. Sto usando l'ultima versione del supporto di Ninject w/asp.net MVC 3.Autorizzazione personalizzata MVC 3 e Ninject IoC

Il problema che ho è che sto usando il constructor injection per iniettare un repository. Ma dal momento in cui viene chiamato OnAuthorization, il repository è nullo. Ecco il codice ...

public class MyAuthorizeAttribute : FilterAttribute, IAuthorizationFilter 
    { 
     private readonly IMyRepo _MyRepo; 

     public MyAuthorizeAttribute() { } 
     public MyAuthorizeAttribute(IMyRepo myRepo) 
     { 
      _MyRepo= myRepo; //this gets initialized 
     } 


     public void OnAuthorization(AuthorizationContext filterContext) 
     { 
      _MyRepo.DoStuff(); //<< Null, wtf 

     } 
    } 

Filtro Binding:

Bind<IMyRepo>().To<MyRepo>().InRequestScope(); 


this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Controller, null).WhenControllerHas<MyAuthorizeAttribute >(); 

Aggiornamento: Una cosa che ho notato è questo filtro è a livello dei controllori. Ho altri filtri a portata di azione che sembrano funzionare correttamente ... potrebbe essere questa la ragione?

Aggiornamento 2: ho confermato che se cambio il campo di applicazione del filtro all'azione, allora il repository è disponibile OnAuthorization (non nullo).

Questo funziona di seguito, tuttavia è necessario per l'ambito del controller, non per l'azione.

this.BindFilter<MyAuthorizeAttribute >(System.Web.Mvc.FilterScope.Action, null).WhenActionMethodHas<MyAuthorizeAttribute >(); 
+0

Sembra che il tuo MyAuthorizeAttribute venga chiamato con il costruttore predefinito. – dexter

+0

@dexter, non pensare che sia il caso. Ho inserito breakpoint e ctor con il repository è chiamato –

+0

Hai impostato il binding del filtro nel modulo Ninject. Guarda il codice di esempio nella sezione "Iniezione delle dipendenze per filtri" in http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for-mvc3/#more-2004 – WorldIsRound

risposta

9

Gli attributi non supportano l'iniezione del costruttore poiché sono creati da .NET Framework e non sono sotto il controllo di Ninject. Se vuoi davvero usare un FilterAttribute (che non consiglio) dovrai usare l'iniezione di proprietà.

Invece continua quello che hai appena iniziato. È necessario un filtro che implementa IAuthorizationFilter (non derivato da FilterAttribute, è sufficiente rimuoverlo dal codice precedente) e inoltre un attributo ordinario per contrassegnare i controller/le azioni.

quindi modificare la rilegatura:

this.BindFilter<MyAuthorizeFilter>(FilterScope.Controller, 0).WhenControllerHas<MyAuthorizeAttribute>(); 

See: https://github.com/ninject/ninject.web.mvc/wiki/MVC3

Il problema con voi implementazione corrente è che si trova una volta come attributo di filtro e una volta aggiunto come normale filtro. Uno per queste istanze avrà il repo iniettato e il repo è nullo per l'altro.

NOTA: è possibile derivare da un FilterAttribute esistente se questo semplifica l'implementazione. Ma non usarlo come attributo in questo caso ma usarlo come filtro ordinario.

+0

Tutto ha senso eccetto per la parte "Note". Solo per curiosità, perché sembra funzionare quando cambio l'ambito di azione anziché il controller? –

+0

La modifica all'azione cambierà nel caso in cui non vi siano più due filtri sul controller ma uno sull'azione (con riferimento al protocollo repo) e uno sul controller (repo == null). Non sono sicuro riguardo all'ordine di esecuzione e se .NET esegue tutti i filtri IAuthorizationFilters o solo finché uno ha esito positivo. Quello sul controller dovrebbe comunque generare un'eccezione NullRef. Ma probabilmente non è eseguito. –

+0

Grazie per la risposta e il follow-up Remo –

6

È consigliabile estendere la classe AuthorizeAttribute in modo che l'autorizzazione funzioni correttamente con le richieste memorizzate nella cache. Sarà inoltre necessario utilizzare Ninject.Web.Mvc

È necessario utilizzare l'iniezione di proprietà Ninject per utilizzare il repository. L'iniezione del costruttore non funziona con gli attributi.

+2

grazie, questo è quello che avevo inizialmente ma poi ho iniziato a ricevere alcune "" Il provider sottostante non è riuscito ad aprire "le eccezioni da EF ... non so se erano correlate all'uso del filtro di autorizzazione o no così ho deciso di provare l'iniezione del ctor e qui Io sono ... –

+0

Ciao Rohan, tanto per essere chiari. L'iniezione del costruttore non funzionerà perché nel costruttore passiamo i valori degli attributi (array params). Anche quando dici iniezione di proprietà - è l'attributo [Inject] sopra la proprietà abbastanza per ottenere ciò con Ninject? Puoi condividere con il binding di Ninject - come è definito. Devi specificare il parametro di input? Ho un problema con un'implementazione simile. Nel mio attributo sto accedendo a dbcontext attraverso i servizi. Il mio dbcontext ha impostato InRequestScope e questo couse un'eccezione che dbcontext sta per essere smaltita. –

+0

che un'eccezione disposta sta accadendo quando ho colpito la mia logica nel filtro. tps: //github.com/ninject/Ninject.Web.Mvc/wiki/Filters-and-Scoped ma non ha molto senso per me esattamente come implementarlo ..... –

0

Ho solo pensato che avrei aggiunto la mia soluzione qui perché sembra funzionare bene.

Creata una classe che estende AuthorizeAttribute e prende l'interfaccia del repository nel costruttore.

Questa classe ignora allora la funzione AuthorizeCore:

public class MyRoleAttribute : AuthorizeAttribute 
{ 
    private ICRepository repository; 

    public MyRoleAttribute(ICRepository Repo) 
    { 
     repository = Repo; 
    } 

protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     //Check if user authenticated 
     if (!httpContext.Request.IsAuthenticated) 
      return false; 

     //Can access items in the query string if needed 
     var id = (httpContext.Request.RequestContext.RouteData.Values["id"] as string) 
     ??(httpContext.Request["id"] as string); 

      //Can access repository that has been injected 
      if (repository.IsGroupCreator(.....)) 
      { 

       return true; 

      } 
      else 
      { 

       return false; 

      } 
    } 
} 

Poi per l'iniezione repository di lavorare ho aggiunto il seguente codice al file NinjectWebCommon.cs MVC:

kernel.BindFilter<MyRoleAttribute>(FilterScope.Action, 0).When(
(controllerContext, actionDescriptor) => actionDescriptor.ActionName == "MyAction"); 

Questo poi mi permette per controllare quali azioni ho bisogno dell'attributo on e ninject si prende cura dell'iniezione del repository. Spero che questo aiuti qualcuno.

Problemi correlati