2013-05-23 3 views
12

Ho alcuni semplici percorsi che desidero limitare tramite un semplice parametro querystring. Se la chiave non è corretta o non è fornita, desidero lanciare un NotAuthorizedException.Devo usare IAuthorizationFilter se desidero creare una risorsa limitata ApiKey con ASP.NET MVC4?

Si prega di non suggerire di utilizzare WebApi o Equiv - Non posso ancora solo in questo scenario.

Quindi non sono sicuro se dovrei implementare uno IAuthorizationFilter o implementare uno IActionFilter o qualcos'altro.

La mia logica di codice?

  • Controllare querystring per chiave.
  • Controllare il mio RavenDb (repository) per un utente con quella chiave/valore.

Se non superano questi controlli, quindi lanciare il NotAuthorizedException.

Suppongo che quindi decorerei un mio metodo di azione con questo filtro. Sto anche assumendo che avrei bisogno di passare nel mio repository anche in questo metodo di azione?

Qualche suggerimento, per favore?

risposta

25

, quindi non sono sicuro se devo essere l'implementazione di un IAuthorizationFilter o l'implementazione di un IActionFilter o anche qualcos'altro.

Si dovrebbe essere l'implementazione di un IAuthorizationFilter:

public class MyAuthorizeAttribute: FilterAttribute, IAuthorizationFilter 
{ 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     var key = filterContext.HttpContext.Request.QueryString["param_name"]; 
     if (!IsValid(key)) 
     { 
      // Unauthorized! 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
    } 

    private bool IsValid(string key) 
    { 
     // You know what to do here => go hit your RavenDb 
     // and perform the necessary checks 
     throw new NotImplementedException(); 
    } 
} 

E se si voleva utilizzare l'iniezione di dipendenza nella vostra filtro azione personalizzata si potrebbe dare un'occhiata al following article in cui è possibile implementare un provider di filtro personalizzato (IFilterProvider). Potresti avere un attributo contrassegnato che puoi utilizzare sulle azioni del controller e poi chiedere a questo fornitore di filtri personalizzati di controllare se l'azione è decorata con questo attributo marker e applicare il filtro di autorizzazione personalizzato.

Ad esempio:

public class MyAuthorizeAttribute: Attribute 
{ 

} 

e il filtro di autorizzazione implementerà solo il IAuthorizationFilter, non sarà un FilterAttribute:

public class MyAuthorizationFilter: IAuthorizationFilter 
{ 
    private readonly ISomeRepository repository; 
    public class MyAuthorizationFilter(ISomeRepository repository) 
    { 
     this.repository = repository; 
    } 

    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     var key = filterContext.HttpContext.Request.QueryString["param_name"]; 
     if (!IsValid(key)) 
     { 
      // Unauthorized! 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
    } 

    private bool IsValid(string key) 
    { 
     // You know what to do here => go hit your RavenDb 
     // and perform the necessary checks 
     throw new NotImplementedException(); 
    } 
} 

e poi si avrà il provider filtro personalizzato:

public class MyFilterProvider : IFilterProvider 
{ 
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) 
    { 
     if (actionDescriptor.GetCustomAttributes(typeof(MyAuthorizeAttribute), true).Any()) 
     { 
      var filter = DependencyResolver.Current.GetService<MyAuthorizationFilter>(); 
      yield return new Filter(filter, FilterScope.Global); 
     } 

     yield break; 
    } 
} 

che sarà registrato in voi r Application_Start:

FilterProviders.Providers.Add(new MyFilterProvider()); 
+0

Grazie al tesoro, Darin! Ho notato che hai usato Property Injection (penso che sia quello che viene chiamato) invece di Constructor Injection - c'è qualche ragione per cui non potrei farlo solo nella classe 'MyAuthorizationFilter' .. e lasciare che' MyAuthorizationFilter' erediti anche il ' FilterAttribute'? Quindi avrei solo 1 lezione, non 2 da fare. –

+0

No, sta usando l'iniezione del costruttore. Questo è ciò che 'DependencyResolver' sta facendo in' MyFilterProvider'.Suppongo che tu non possa usare una singola classe poiché il framework non costruisce attributi usando DependencyResolver e come tale, non puoi decorare le tue azioni con esso perché ha bisogno di un 'Repository' passato al costruttore e tu non ne avrà uno disponibile. C'è un modo migliore per fare l'iniezione del costruttore sugli attributi dato che questa implementazione renderà piuttosto difficile fare cose come '[MyAuthorize (ErrorMessage =" Sad panda ")]'. – ajbeaven

+0

@ajbeaven È possibile impostare l'attributo con i parametri come si desidera, quindi impostarli come proprietà interne e ottenere l'attributo all'interno di authorizationFilter per ottenere l'accesso alle proprietà/campi. Usa 'filterContext.ActionDescriptor.GetCustomAttributes (typeof (YourClass), true) .Cast ();' per ottenere l'attributo. L'ambito interno è utile se hai un progetto dedicato per loro; altrimenti, crea semplicemente getter. –