2012-01-12 3 views
10

Qui ci sono le mie esigenze:Creazione di un AuthorizeAttribute - cosa devo sapere?

  • sarò aggiungendo agli utenti di N quantità di ruoli; definito in un database.

  • Devo proteggere ogni azione del controller con il mio attributo authorize.

Ad esempio, l'applicazione web sarebbe controllare se l'utente collegato appartiene a uno di questi due ruoli e se lo fanno, io li lascio in. Come posso dire al Autorizza attributo per andare a prendere i ruoli utente da una tabella di database che scelgo?

[Authorize(Roles = "Admin, Technician")] 
public ActionResult Edit(int id) 
{ 
    return View(); 
} 

Ho provato Googling per molte pagine diverse, ma nessuno sembra in sintonia con quello che mi serve e sono eccessivamente complicato.

Se il official documentation ha qualcosa che mi piacerebbe trovarlo, come non ho visto nulla che potrei usare.

Qualche suggerimento?

Ad esempio, questa domanda ha una risposta molto chiara, ma non so se è completa o manca qualcosa di importante.

ASP.NET MVC3 Role and Permission Management -> With Runtime Permission Assignment


Modifica

Sembra che quello che sto effettivamente cercando è la creazione di un provider di ruoli personalizzato, giusto? Devo necessario per implementare questa classe e utilizzarla come il mio fornitore di ruolo? Sono abbastanza nuovo in questo, qualche pensiero?

http://msdn.microsoft.com/en-us/library/8fw7xh74.aspx

risposta

0

Ci sono un sacco di modi per gestire questo. Il metodo di Darin ei suoi blowdarts (entrambi gli individui molto esperti - uno di questi è anche un autore di sicurezza) sono decenti nel link che hai fornito.

Una cosa da tenere d'occhio è il cache. Se si utilizza la cache di outputcache lato server, è possibile che venga inavvertitamente memorizzato nella cache qualcosa per un utente che viene restituito a un altro utente. Si prega di consultare:

OutputCache and Authorize filters in MVC3

e

Why can't I combine [Authorize] and [OutputCache] attributes when using Azure cache (.NET MVC3 app)?

e

MVC Custom Authentication, Authorization, and Roles Implementation

per ulteriori informazioni su questo e come gestire la cache se si utilizza un attributo Autorizza.

0

È possibile utilizzare il provider di appartenenze predefinito e il provider di ruolo, anziché implementare il proprio, ma è necessario utilizzare anche il database di appartenenza asp.net predefinito, aspnetdb.mdf.

Vedi here per una procedura dettagliata

9

Vado attraverso più o meno lo stesso scenario degli ultimi due settimane, quindi questo potrebbe aiutare qualcun altro nella stessa barca. Il mio scenario è un'applicazione MVC4 su una intranet aziendale con gli utenti archiviati in Active Directory. Ciò consente all'autenticazione di Windows che fornisce il Single Sign-On, quindi non è necessaria l'autenticazione basata su form. I ruoli sono memorizzati in un database Oracle. Ho 3 ruoli:

  • Readonly: Tutti gli utenti hanno bisogno di essere un membro di questo per accedere all'applicazione
  • dell'utente: Creare nuove resords
  • Amministrazione: Modifica ed eliminare record

I ho deciso di utilizzare il API del provider di ruoli asp.net per creare il mio AccountRoleProvider. Finora ho solo bisogno di utilizzare 2 metodi in questo, GetRolesForUser e IsUserInRole:

public class AccountRoleProvider : RoleProvider // System.Web.Security.RoleProvider 
{ 
    private readonly IAccountRepository _accountRepository; 

    public AccountRoleProvider(IAccountRepository accountRepository) 
    { 
     this._accountRepository = accountRepository; 
    } 

    public AccountRoleProvider() : this (new AccountRepository()) 
    {} 

    public override string[] GetRolesForUser(string user521) 
    { 
     var userRoles = this._accountRepository.GetRoles(user521).ToArray(); 

     return userRoles; 
    } 

    public override bool IsUserInRole(string username, string roleName) 
    { 
     var userRoles = this.GetRolesForUser(username); 

     return Utils.IndexOfString(userRoles, roleName) >= 0; 
    } 
} 

ho aggiornato il web.config di usare il mio provider di ruoli:

<authentication mode="Windows" /> 
<roleManager enabled="true" defaultProvider="AccountRoleProvider"> 
    <providers> 
    <clear/> 
    <add name="AccountRoleProvider" 
     type="MyApp.Infrastructure.AccountRoleProvider" /> 
    </providers> 
</roleManager> 

Poi ho creato attributi 2 personalizzato da AuthorizeAttribute , ReadOnlyAuthorize e CustomAuthorize.

ReadonlyAuthorize:

public class ReadonlyAuthorize : AuthorizeAttribute 
{ 
    private IAccountRepository _accountRepository; 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var user = httpContext.User; 
     this._accountRepository = new AccountRepository(); 

     if (!user.Identity.IsAuthenticated) 
     { 
      return false; 
     } 

     // Get roles for current user 
     var roles = this._accountRepository.GetRoles(user.Identity.Name); 

     if (!roles.Contains("readonly")) 
     { 
      return false; 
     } 

     return base.AuthorizeCore(httpContext); 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult) 
     { 
      filterContext.Result = new ViewResult { ViewName = "AccessDenied" }; 
     } 
    } 
} 

CustomAuthorize:

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public string RedirectActionName { get; set; } 
    public string RedirectControllerName { get; set; } 
    private IAccountRepository _accountRepository; 

    protected override bool AuthorizeCore(HttpContextBase httpContext) 
    { 
     var user = httpContext.User; 
     this._accountRepository = new AccountRepository(); 
     var accessAllowed = false; 

     // Get the roles passed in with the (Roles = "...") on the attribute 
     var allowedRoles = this.Roles.Split(','); 

     if (!user.Identity.IsAuthenticated) 
     { 
      return false; 
     } 

     // Get roles for current user 
     var roles = this._accountRepository.GetRoles(user.Identity.Name); 

     foreach (var allowedRole in allowedRoles) 
     { 
      if (roles.Contains(allowedRole)) 
      { 
       accessAllowed = true; 
      } 
     } 

     if (!accessAllowed) 
     { 
      return false; 
     } 

     return base.AuthorizeCore(httpContext); 
    } 

    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (filterContext.HttpContext.User.Identity.IsAuthenticated && filterContext.Result is HttpUnauthorizedResult) 
     { 
      var values = new RouteValueDictionary(new 
      { 
       action = this.RedirectActionName == string.Empty ? "AccessDenied" : this.RedirectActionName, 
       controller = this.RedirectControllerName == string.Empty ? "Home" : this.RedirectControllerName 
      }); 

      filterContext.Result = new RedirectToRouteResult(values); 
     } 
    } 
} 

La ragione per 2 diversi attributi è che uso uno per il ruolo Readonly che tutti gli utenti devono essere membri per accedere al app. Posso aggiungere questo nel metodo RegisterGlobalFilters in Global.asax che significa che è applicato automaticamente a tutti i controller:

public static void RegisterGlobalFilters(GlobalFilterCollection filters) 
{ 
    filters.Add(new HandleErrorAttribute()); 
    filters.Add(new ReadonlyAuthorize()); 
} 

Poi nel CustomAuthorize posso adottare un approccio più granulare e specificare i ruoli che voglio e si applicano a una Controller o una singola azione es di seguito posso limitare l'accesso al metodo Delete per gli utenti nel ruolo di amministratore:

[AccessDeniedAuthorize(RedirectActionName = "AccessDenied", RedirectControllerName = "Home", Roles = "Admin")] 
public ActionResult Delete(int id = 0) 
{ 
    var batch = myDBContext.Batches.Find(id); 
    if (batch == null) 
    { 
     return HttpNotFound(); 
    } 

    return View(batch); 
} 

Non ci sono ulteriori passi che devo prendere come l'aggiornamento l'oggetto Utente con i ruoli che l'utente corrente è un membro di. Ciò recupererà i ruoli per l'utente una volta invece che ogni volta nei miei attributi personalizzati e utilizzerà anche User.IsInRole. Qualcosa di simile dovrebbe essere possibile in Application_AuthenticateRequest in Gloal.asax:

var roles = "get roles for this user from respository"; 

if (Context.User != null) 
    Context.User = new GenericPrincipal(Context.User.Identity, roles);