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

发布于 2024-11-10 01:44:14 字数 2487 浏览 2 评论 0原文

我正在使用 MVC3 的 MVC 站点地图,但遇到问题。 考虑以下站点地图文件:

<?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>

当我加载网页时,我只得到以下选项:

Today1、Today2、Today3、Today4

但不显示Today。这是控制器上的操作,而其他操作不存在。为什么它隐藏控制器上实际存在的项目?我取消了控制器上的授权,以排除它与授权有任何关系,但效果仍然相同。

这是站点地图配置(在 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>

I'm using MVC sitemap for MVC3 but having problems with it.
Consider the following sitemap file:

<?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>

When I load my web page up I only get the following options:

Today1, Today2, Today3, Today4

But Today is not displayed. This is an action on a controller whereas the other actions don't exist. Why is it hiding the item which actually exists on the controller? I took off authorization on the controller to rule out it had anything to do with authorization but still same effect.

This is the sitemap config (set in 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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

感悟人生的甜 2024-11-17 01:44:14

我找出问题所在了。
HttpContext 用户的 InRole() 方法在库代码内的 MvcSiteMapProvider.DefaultAclModule 中使用。
我正在使用表单身份验证,这意味着 InRole 永远不会工作,因为未设置用户上下文上的角色属性(它不知道如何应用角色)。

我可以编写自己的 aclmodule 提供程序来检查票证中存储的角色的身份验证票证,或者对于 global.asax 中的每个身份验证请求事件,使用角色集设置上下文。最后我选择了后者:

eg

  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);
                }
            }
        }

I find out the problem.
The HttpContext user's InRole() method is used in the MvcSiteMapProvider.DefaultAclModule within the library code.
I am using Forms Authentication which means the InRole will never work as the roles property on the user context is not set (it doesn't know how roles are applied).

I could either write my own aclmodule provider which checks the authentication ticket for the roles stored within the ticket, or alternatively for every authentication request event in global.asax, set the context with the roles set. In the end I chose the latter:

e.g.

  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);
                }
            }
        }
相守太难 2024-11-17 01:44:14

@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 中指定实现的控制器应该可以达到目的。

@jaffa, your approach helped me !! thanks. Here, is how I implemented it.. maybe it can help others too!

public class MenuVisibilityController : Controller, ISiteMapNodeVisibilityProvider
{
    public bool IsVisible(SiteMapNode Node, HttpContext context, IDictionary<string, object> sourceMetadata)
    {
        return context.User.Identity.IsAuthenticated;
    }
}

Implemented Visibility Provider for MVC sitemap and then used it for visibility of a particular node like below:

<mvcSiteMapNode title="Test Menu" controller="Account" action="Index" visibilityProvider="MyProject.Controllers.MenuVisibilityController, MyProject">
  <mvcSiteMapNode title="Test Item 1" controller="Account" action="GetItems" />
</mvcSiteMapNode>

specifying implemented controller in VisibilityProvider should serve the purpose.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文