If I understand you correctly you want to display the items the user does not have access to in a particular way? You can change the access level filtering by setting the RequiredAccess property on the MenuList. After that you need to find out which ones the user does not have access to and add a particular HTML class to that item to style it differently.
Frederik
Thanks a lot Fredrik. You understood me correct. However there is still a problem regarding submenus.
I'm using nested Menulist to have the functionality of RequiredAccess for submenus as well. But then I get AccessDeniedException.
I wrapped the code behind functionality in a try catch block, but then I got a new exception on Menulist.visable=true;
I've read on your blog http://www.frederikvig.com/2009/08/episerver-web-controls-menulist-and-pagetree/
that it's customary to use the pagetree as submenu, but can't see that Pagetree have RequiredAccess functionality.
Thanks! I changed from Menulist to Pagetree, but I still get access denied when databinding to the top menu.
<EPiServer:PageTree ID="pagetree1" runat="server" Visible="True" RequiredAccess="NoAccess" EnableViewState="True" EnableVisibleInMenu="True"> <HeaderTemplate> <ul id="nav" class="clearfix"> <li class="<%#(CurrentPage.PageLink.ID == EPiServer.Core.PageReference.StartPage.ID) ? "active" : "" %>"> <EPiServer:Property ID="Property3" runat="server" PropertyName="PageLink" PageLink='<%#EPiServer.Core.PageReference.StartPage %>' /> </li> </HeaderTemplate> <ItemTemplate> <li class="<%#SecurityHelper.HasAccess(Container.CurrentPage) ? "" : "unavailable" %>"> <EPiServer:Property ID="Property1" runat="server" PropertyName="PageLink" /> <EPiServer:PageTree ID="pagetree2" runat="server" PageLink='<%#Container.CurrentPage.PageLink %>' RequiredAccess="NoAccess"> <HeaderTemplate> <ul> </HeaderTemplate> <SelectedItemTemplate> <li class="active"> <EPiServer:Property ID="Property3" runat="server" PropertyName="PageLink" /> </li> </SelectedItemTemplate> <ItemTemplate> <li class="<%#SecurityHelper.HasAccess(Container.CurrentPage) ? "" : "unavailable" %>"> <EPiServer:Property ID="Property1" runat="server" PropertyName="PageLink" /> </li> </ItemTemplate> <FooterTemplate> </ul></FooterTemplate> </EPiServer:PageTree> </li> </ItemTemplate> <SelectedExpandedTopTemplate> <li class="active"> <EPiServer:Property ID="Property3" runat="server" PropertyName="PageLink" /> <EPiServer:PageTree ID="pagetree3" runat="server" PageLink='<%#Container.CurrentPage.PageLink %>' RequiredAccess="NoAccess"> <HeaderTemplate> <ul> </HeaderTemplate> <SelectedItemTemplate> <li class="active"> <EPiServer:Property ID="Property3" runat="server" PropertyName="PageLink" /> </li> </SelectedItemTemplate> <ItemTemplate> <li class="<%#SecurityHelper.HasAccess(Container.CurrentPage) ? "" : "unavailable" %>"> <EPiServer:Property ID="Property1" runat="server" PropertyName="PageLink" /> </li> </ItemTemplate> <FooterTemplate> </ul></FooterTemplate> </EPiServer:PageTree> </li> </SelectedExpandedTopTemplate> <FooterTemplate> </ul> </FooterTemplate> </EPiServer:PageTree>
pagetree1.Visible = true; pagetree1.PageLink = EPiServer.Core.PageReference.StartPage; pagetree1.DataBind();
I changed the top level control to Pagetree as well, but that didn't help either.
SDK says that the top level should be Menulist and subnodes should be Pagetree which is current status on my pagetype
I guess the clue is how to get around the exception in the function below, but how!?
/// <summary>
/// Retrieves a PageData object based on supplied <see cref="EPiServer.Core.PageReference"/>
/// argument (from <see cref="EPiServer.Core.IPageSource"/>).
/// </summary>
/// <param name="pageLink"></param>
/// <returns>Returns the PageData object for the specified EPiServer.Core.PageReference argument.</returns>
/// <example>
/// The following code example demonstrates the usage of <b>GetPage</b> to retrieve the <b>PageData</b>
/// object for the current page.
/// <code>EPiServer PageData tmpPageData = GetPage( CurrentPageLink );</code>
/// The following code example demonstrates the usage of <b>GetPage</b> and <b>CurrentPage</b>
/// to retrieve <b>PageData</b> information for the page specified in the <b>EventsContainer</b> attribute.
/// <code source="../CodeSamples/EPiServer/PageBaseSamples.cs" region="GetPage" lang="cs" />
/// </example>
public virtual PageData GetPage(PageReference pageLink)
{
if (IsDesignMode)
{
return new PageData();
}
PageData page = DataFactory.Instance.GetPage(pageLink);
// Check if the user has access to the page
AccessLevel requiredAccess = (pageLink.ID == CurrentPageLink.ID) ? RequiredAccess() : AccessLevel.Read;
if (!page.GetSecurityDescriptor().HasAccess(PrincipalInfo.CurrentPrincipal, requiredAccess))
{
// If the user is already logged in, throw exception
if (PrincipalInfo.CurrentPrincipal.Identity.IsAuthenticated)
{
throw new AccessDeniedException();
}
// If not logged in, make sure they get a graceful login screen
AccessDenied();
}
return page;
}
If you use a Repeater instead inside your ItemTemplate it should work. The access exception is thrown when the inner PageTree is databound for parent pages that the user does not have access to (this is for MenuList and PageTree, if you call DataFactory.Instance.GetChildren directly it works fine since it won't filter out non-published and noaccess pages).
The only thing we're missing in the Repeater is a SelectedTemplate. In the Extensions for EPiServer CMS library I have an extension method that does this for me (see The SelectedTemplate and duplicate code).
<ItemTemplate> <li class="<%#SecurityHelper.HasAccess(Container.CurrentPage) ? "" : "unavailable" %>"> <EPiServer:Property ID="Property1" runat="server" PropertyName="PageLink" /> <asp:Repeater runat="server" DataSource="<%# EPiServer.DataFactory.Instance.GetChildren(Container.CurrentPage.PageLink) %>"> <HeaderTemplate> <ul> </HeaderTemplate> <ItemTemplate> <li class="<%#SecurityHelper.HasAccess((PageData)Container.DataItem) ? "" : "unavailable" %> <%# IsSelected((PageData)Container.DataItem) %>"> <EPiServer:Property ID="Property1" runat="server" PropertyName="PageLink" /> </li> </ItemTemplate> <FooterTemplate> </ul></FooterTemplate> </asp:Repeater> </li> </ItemTemplate>
Frederik
Hello fellow developers! :)
I'm trying to mange the Menulist and accessrights. I know that the Menulist by default doesn't return menuitems that the user doesn't have access to, but I want to show it and make it disabled. The purpose is that the customer should be able to see all titles and buy what ever titles that is interesting.
I therefore want to control the menuitem and make it disabled, but at long as the menulist doesn't show items the user have no access to, I have a problem.
Do I use RestrictAccess on Menuitem to control this??
Kind regards,
Jon Haakon