2011-12-07 52 views
14

Estoy trabajando en un sitio ASP.Net MVC 3. La vista principal _Layout contiene un menú y quiero ocultar algunos de los elementos del menú en base a si se ha identificado y qué funciones que se encuentre.ASP.Net MVC Ocultar/Mostrar elementos del menú según la seguridad

Esto funciona actualmente utilizando un código como éste

@if (HttpContext.Current.User.Identity.IsAuthenticated) 
{ 
    <li id="MyLearningTab">@Html.ActionLink("My Learning", "MyLearning", "Learning")</li> 
    if (HttpContext.Current.User.IsInRole("Reporters")) 
    { 
     <li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li> 
    } 
    if (HttpContext.Current.User.IsInRole("Administrators")) 
    { 
     <li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li> 
     <li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li> 
    } 
} 

me gustaría refactorizar esto en algo más legible y se acercó con algo como esto

@if ((bool)ViewData["MenuMyLearning"]){<li id="MyLearningTab">@Html.ActionLink("My Learning", "MyLearning", "Learning")</li> }  
@if((bool)ViewData["MenuReports"]){<li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li>} 
@if ((bool)ViewData["MenuDashboard"]){<li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li>} 
@if ((bool)ViewData["MenuAdmin"]){<li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li>} 

originalmente añade lo siguiente a mi base de pensamiento controlador constructor pude configurar el ViewData para estas propiedades allí

ViewData["MenuDashboard"] = User != null && User.Identity.IsAuthenticated && User.IsInRole("Administrators"); 
ViewData["MenuAdmin"] = User != null && User.Identity.IsAuthenticated && User.IsInRole("Administrators"); 
ViewData["MenuReports"] = User != null && User.Identity.IsAuthenticated && User.IsInRole("Reportors"); 
ViewData["MenuMyLearning"] = User != null && User.Identity.IsAuthenticated; 

Sin embargo, resulta que el objeto Usuario es nulo en este momento en el ciclo de vida. También intenté crear un filtro global personalizado, pero ViewData no es accesible.

¿Cuál es la forma recomendada de hacer algo como esto? ¿Debería dejarlo como estaba al principio con todo el código HttpContext en la vista?

+0

Aquí hay otra solución http://stackoverflow.com/questions/17012643/role -based-navigation –

Respuesta

8

Esto es lo que terminé haciendo. Creé una clase de ayuda llamada MenuSecurity con propiedades booleanas estáticas para cada elemento del menú que muestra qué elementos deberían ser visibles. Cada propiedad se veía así

public static bool DashboardVisible 
{ 
    get 
    { 
     return 
     HttpContext.Current.User != null && 
     HttpContext.Current.User.Identity.IsAuthenticated; 
    } 
} 

entonces me puso en orden mi menú vista parcial a tener este aspecto

@if (MenuSecurity.ReportsVisible){<li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li>} 
@if (MenuSecurity.DashboardVisible){<li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li>} 
@if (MenuSecurity.AdminVisible){<li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li>} 
+0

Creo que solo tienes 3 grupos. pero ¿qué pasará si tienes 20 - 30 grupos? – kbvishnu

9

Recomendaciones generales sobre los roles

La forma en que he hecho es crear un principal personalizado y para almacenar la información adicional requerida allí. En su ejemplo, esto al menos incluiría los roles para el usuario. De esta forma evitará hacer muchos viajes adicionales a la tienda de usuarios (que probablemente sea una base de datos SQL).

tienen esta pregunta mía en la que le doy al código que estoy utilizando con éxito un vistazo a: Is this Custom Principal in Base Controller ASP.NET MVC 3 terribly inefficient?

en cuenta que estoy almacenando el director de costumbre en la memoria caché en lugar de en la sesión (siendo paranoico sobre el secuestro de la sesión).

Me gusta este enfoque, ya que es muy extensible. Por ejemplo, desde entonces extendí esto para exponer las credenciales de Facebook cuando el usuario inicia sesión a través de Facebook.

¡Recuerde que si está almacenando datos en caché, debe recordar actualizarlos cuando cambien!

respuesta a su pregunta

Sólo para añadir, en su caso específico, probablemente debería almacenar esta información adicional en un ViewModel y luego su vista decía cosas como:

@if(ShowReports) { <li id="ReportTab">@Html.ActionLink("Reports", "Index", "Reports")</li> } 
@if(ShowDashboard) { <li id="DashboardTab">@Html.ActionLink("Dashboard", "Dashboard", "Admin")</li> } 
@if(ShowAdmin { <li id="AdminTab">@Html.ActionLink("Admin", "Index", "Admin")</li> } 

con el Código de ViewModel que dice algo así como:

public bool ShowReports {get;set;} 
public bool ShowDashboard {get;set;} 
public bool ShowAdmin {get;set;} 

public void SetViewModel() 
{ 
    if (User.Identity.IsAuthenticated) 
    { 
    if (HttpContext.Current.User.IsInRole("Reporters")) 
    { 
     ShowReports = true; 
    } 
    if (HttpContext.Current.User.IsInRole("Administrators")) 
    { 
     ShowDashboard = true; 
     ShowAdmin = true; 
    } 
    } 
} 

En realidad, tiendo a tomar este st ep más y crear un ReportsLink en mi ViewModel y configurarlo para que contenga el enlace si el usuario está autorizado o para ser una cadena vacía si no lo están. A continuación, la vista se limita a decir:

@Model.ReportsLink 
@Model.DashboardLink 
@Model.AdminLink 

En ese caso, la parte pertinente del modelo de vista podría ser así:

ReportLink = new MvcHtmlString(HtmlHelper.GenerateLink(HttpContext.Current.Request.RequestContext, System.Web.Routing.RouteTable.Routes, "linktext", "routename", "actionname", "controllername", null, null)); 
+0

¿A dónde llama SetViewModel() desde ??? – dannyrosalex

Cuestiones relacionadas