In altre parole, è un'idea davvero stupida?Come si crea un AuthorizeAttribute personalizzato specifico per area, controller e azione?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeActionAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
// get the area, controller and action
var area = filterContext.RouteData.Values["area"];
var controller = filterContext.RouteData.Values["controller"];
var action = filterContext.RouteData.Values["action"];
string verb = filterContext.HttpContext.Request.HttpMethod;
// these values combined are our roleName
string roleName = String.Format("{0}/{1}/{2}/{3}", area, controller, action, verb);
// set role name to area/controller/action name
this.Roles = roleName;
base.OnAuthorization(filterContext);
}
}
UPDATE Sto cercando di evitare quanto segue, in uno scenario in cui si abbiano i permessi di ruolo estremamente granulari, perché i ruoli sono impostati su una base per-client e attaccati a gruppi di utenti:
public partial class HomeController : Controller
{
[Authorize(Roles = "/supplierarea/homecontroller/indexaction/")]
public virtual ActionResult Index()
{
return View();
}
[Authorize(Roles = "/supplierarea/homecontroller/aboutaction/")]
public virtual ActionResult About()
{
return View();
}
}
Qualcuno può illuminarmi in modo sicuro per scrivere questo AuthorizeRouteAttribute per accedere alle informazioni sul percorso e utilizzarlo come nome del ruolo? Come dice Levi, il RouteData.Values non è sicuro.
L'utilizzo dell'esecuzione di httpContext.Request.Path è più sicuro o migliore?
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
// auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
return;
}
var path = filterContext.HttpContext.Request.Path;
var verb = filterContext.HttpContext.Request.HttpMethod;
// these values combined are our roleName
string roleName = String.Format("{0}/{1}", path, verb);
if (!filterContext.HttpContext.User.IsInRole(roleName))
{
// role auth failed, redirect to login page
filterContext.Result = new HttpUnauthorizedResult();
// P.S. I want to tell the logged in user they don't
// have access, not ask them to login. They are already
// logged in!
return;
}
//
base.OnAuthorization(filterContext);
}
Questo illustra forse il problema un po 'più:
enum Version
{
PathBasedRole,
InsecureButWorks,
SecureButMissingAreaName
}
string GetRoleName(AuthorizationContext filterContext, Version version)
{
//
var path = filterContext.HttpContext.Request.Path;
var verb = filterContext.HttpContext.Request.HttpMethod;
// recommended way to access controller and action names
var controller =
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
var action =
filterContext.ActionDescriptor.ActionName;
var area = "oh dear...."; // mmmm, where's thearea name???
//
var insecureArea = filterContext.RouteData.Values["area"];
var insecureController = filterContext.RouteData.Values["controller"];
var insecureAction = filterContext.RouteData.Values["action"];
string pathRoleName =
String.Format("{0}/{1}", path, verb);
string insecureRoleName =
String.Format("{0}/{1}/{2}/{3}",
insecureArea,
insecureController,
insecureAction,
verb);
string secureRoleName =
String.Format("{0}/{1}/{2}/{3}",
area,
controller,
action,
verb);
string roleName = String.Empty;
switch (version)
{
case Version.InsecureButWorks:
roleName = insecureRoleName;
break;
case Version.PathBasedRole:
roleName = pathRoleName;
break;
case Version.SecureButMissingAreaName:
// let's hope they don't choose this, because
// I have no idea what the area name is
roleName = secureRoleName;
break;
default:
roleName = String.Empty;
break;
}
return roleName;
}
Si prega di aggiungere alla risposta per mostrare come il vostro suggerimento funziona in codice? Stiamo usando le aree, quindi dovrebbe riflettere questo come i controllori e le azioni. Per disinteresse, puoi realmente condividere una corrispondenza con un controller o un'azione (ad esempio, come suggerito:/myarea/mycontroller/myaction '; membri di DROP TABLE; - /)? Sicuramente MVC non corrisponderà al controller o all'azione in primo luogo? – Junto
Risposta aggiornata per rispondere alla tua domanda. – Levi
Ciao Levi, ho capito che posso usare (string controller = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; string action = filterContext.ActionDescriptor.ActionName;) ma non riesco ad accedere al nome dell'area nello stesso modo. Tuttavia, non è disponibile alcun AreaName. Dove posso individuarlo? Un semplice esempio di codice chiuderebbe questa domanda. – Junto