为什么MVC网站地图会隐藏控制器上存在操作的菜单项?

问题描述

| 我正在将MVC网站地图用于MVC3,但存在问题。 考虑以下站点地图文件
<?xml version=\"1.0\" encoding=\"utf-8\" ?>
<mvcSiteMap xmlns=\"http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0\" enableLocalization=\"true\">
  <mvcSiteMapNode title=\"Home\" controller=\"Home\" action=\"Index\" changeFrequency=\"Always\" updatePriority=\"normal\" Description=\"Test HOME\">
    <mvcSiteMapNode title=\"Today\" controller=\"Dashboard\" action=\"Today\" />
    <mvcSiteMapNode title=\"Today1\" controller=\"Dashboard\" action=\"Today1\" />
    <mvcSiteMapNode title=\"Today2\" controller=\"Dashboard\" action=\"Today2\" />
    <mvcSiteMapNode title=\"Today3\" controller=\"Dashboard\" action=\"Today3\" />
    <mvcSiteMapNode title=\"Today4\" controller=\"Dashboard\" action=\"Today4\" />   
  </mvcSiteMapNode>
</mvcSiteMap>
当我加载网页时,我只会得到以下选项: 今天1,今天2,今天3,今天4 但是今天不显示。这是控制器上的一个动作,而其他动作不存在。为什么它隐藏了控制器上实际存在的项目?我在控制器上取消了授权,以排除它与授权有关,但效果仍然相同。 这是站点地图配置(在web.config中设置):
  <siteMap defaultProvider=\"MvcSiteMapProvider\" enabled=\"true\">
      <providers>
        <clear />
        <add name=\"MvcSiteMapProvider\" 
             type=\"MvcSiteMapProvider.DefaultSiteMapProvider,MvcSiteMapProvider\" 
             siteMapFile=\"~/Mvc.Sitemap\" 
             securityTrimmingEnabled=\"true\" 
             cacheDuration=\"5\" 
             enableLocalization=\"true\"
             scanAssembliesForSiteMapNodes=\"false\" 
             includeAssembliesForScan=\"\" 
             excludeAssembliesForScan=\"\" 
             attributesToIgnore=\"visibility\" 
             nodeKeyGenerator=\"MvcSiteMapProvider.DefaultNodeKeyGenerator,MvcSiteMapProvider\" 
             controllerTypeResolver=\"MvcSiteMapProvider.DefaultControllerTypeResolver,MvcSiteMapProvider\" 
             actionMethodParameterResolver=\"MvcSiteMapProvider.DefaultActionMethodParameterResolver,MvcSiteMapProvider\" 
             aclModule=\"MvcSiteMapProvider.DefaultAclModule,MvcSiteMapProvider\" 
             siteMapNodeUrlResolver=\"MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver,MvcSiteMapProvider\" 
             siteMapNodeVisibilityProvider=\"MvcSiteMapProvider.DefaultSiteMapNodeVisibilityProvider,MvcSiteMapProvider\" 
             siteMapProviderEventHandler=\"MvcSiteMapProvider.DefaultSiteMapProviderEventHandler,MvcSiteMapProvider\" />
      </providers>      
    </siteMap>
  </system.web>
    

解决方法

我找出问题所在。 库代码中的MvcSiteMapProvider.DefaultAclModule中使用HttpContext用户的InRole()方法。 我正在使用表单身份验证,这意味着InRole将永远无法工作,因为未设置用户上下文上的role属性(它不知道角色的应用方式)。 我可以编写我自己的aclmodule提供程序,该程序检查身份验证票证中存储的票证中的角色,或者针对global.asax中的每个身份验证请求事件,使用角色集设置上下文。最后,我选择了后者: 例如
  if (HttpContext.Current.User != null)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if (HttpContext.Current.User.Identity is FormsIdentity)
                {                     
                    FormsIdentity formsId = (FormsIdentity)HttpContext.Current.User.Identity;
                    FormsAuthenticationTicket ticket = formsId.Ticket;

                    // need to do this so MVC sitemap IsInRole works inside default acl module: MvcSiteMapProvider.DefaultAclModule
                    var authData = new AuthenticationModel(ticket.UserData);
                    var roles = new List<string>(authData.EffectiveRoles).ToArray();
                    HttpContext.Current.User = new GenericPrincipal(formsId,roles);
                }
            }
        }
    ,@jaffa,您的方法帮助了我!谢谢。这就是我的实现方式。也许它也可以帮助其他人!
public class MenuVisibilityController : Controller,ISiteMapNodeVisibilityProvider
{
    public bool IsVisible(SiteMapNode Node,HttpContext context,IDictionary<string,object> sourceMetadata)
    {
        return context.User.Identity.IsAuthenticated;
    }
}
为MVC站点地​​图实现了可见性提供程序,然后将其用于特定节点的可见性,如下所示:
<mvcSiteMapNode title=\"Test Menu\" controller=\"Account\" action=\"Index\" visibilityProvider=\"MyProject.Controllers.MenuVisibilityController,MyProject\">
  <mvcSiteMapNode title=\"Test Item 1\" controller=\"Account\" action=\"GetItems\" />
</mvcSiteMapNode>
在VisibilityProvider中指定实现的控制器应达到目的。