Po chvilce bojů a objevení několika bugů se mi nakonec podařilo rozchodit lokalizaci a autorizaci v site-mapách ASP.NET, konkrétně při použití defaultního XmlSiteMapProvider a web.sitemap souborů (částečně to lze ovšem aplikovat i na jiné providery).
Lokalizace website.map
Defaultní XmlSiteMapProvider přímo podporuje lokalizaci web.sitemap souborů, stačí rootovému elementu nastavit atribut enableLocalization=“true“ a dále se pak na resources můžeme explicitně odkazovat obdobně jako v .aspx souborech, přes výraz $resources:ClassName,KeyName,DefaultValue
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" enableLocalization="true"> <siteMapNode title="$resources: Navigation, UvodniStranka" url="~/default.aspx"> ... </siteMap>
Výše uvedený příklad by se opíral o soubor ~/App_GlobalResources/Navigation.resx. Jedná se o explicitní způsob lokalizace, existuje ještě implicitní metodika s využitím atributu resourceKey, nicméně implicitní lokalizace jako taková mě neoslovuje, takže ani tentokrát nebudu podorbněji rozvádět.
Pozor také, že mezi dolarem ($) a klíčovým slovem resources nesmí být mezerník. Lokalizovat lze výše uvedeným způsobem atributy title a description, bohužel ne url. Atribut url takto lokalizovat bohužel nelze, ač je to v některých dokumentacích uvedeno.
Pokud bychom chtěli lokalizovat i URL, můžeme to zařídit například tak, že nakonfigurujeme přes web.config dva nezávislé SiteMapProvidery, kde každý bude ukazovat na jiný .sitemap soubor:
<siteMap defaultProvider="CzXmlSiteMapProvider" enabled="true"> <providers> <add name="CzXmlSiteMapProvider" description="Provider pro cestinu." type="System.Web.XmlSiteMapProvider" siteMapFile="WebCz.sitemap" securityTrimmingEnabled="true" /> <add name="EnXmlSiteMapProvider" description="Provider pro cestinu." type="System.Web.XmlSiteMapProvider" siteMapFile="WebEn.sitemap" securityTrimmingEnabled="true" /> </providers> </siteMap>
…následně bychom podle aktuálního jazyka museli controlu SiteMapDataSource explicitně nastavovat příslušný SiteMapProvider (nastavit property SiteMapDataSource.SiteMapProvider, typ string). Deklaratorně například fíglem:
<asp:SiteMapDataSource ID="SiteMapDS" SiteMapProvider="<%$ Resources: Navigation, SiteMapProvider %>" runat="server" />
Viz též obecná lokalizace webových aplikací.
Autorizace – skrývání uživateli nepřístupných položek
XmlSiteMapProvider, přesněji řečeno už bázová třída SiteMapProvider podporuje i authorizaci, resp. skrývání uživateli nedostupných položek. Tato funkčnost je řízena přes property SiteMapProvider.SecurityTrimmingEnabled, která se však nenastavuje programově (má jen get), nýbrž přes konfiguraci provideru z web.config souboru, atributem securityTrimmingEnabled:
<siteMap defaultProvider="MyXmlSiteMapProvider" enabled="true"> <providers> <clear/> <add name="MyXmlSiteMapProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="~/Web.sitemap" securityTrimmingEnabled="true" /> </providers> </siteMap>
Pokud nastavíme tento atribut, pravděpodobně nám začně funkčnost ihned fungovat. SiteMapProvider si sám hlídá přístupová práva uživatele nastavená přes sekci<authorization /> web.configu a uživateli nepřístupné položky skrývá.
Ovšem pozor!!! Implementace tohoto hlídání není úplně korektní a má problém s authorization pravidly web.config souborů, která se přes <location /> odkazují na podsložky. Chceme-li tedy tuto funkčnost SiteMapProvideru využít, můžeme ve web.config souborech definovat <location /> pravidla pouze pro jednotlivé soubory v příslušné složce a přístupová práva složek jako takových musíme řídit přes samostatné web.config soubory v těchto složkách!!!
Podle dokumentace a schématu .sitemap souboru má existovat u elementu <siteMapNode /> i atribut securityTrimmingEnabled, jakékoliv použití tohoto atributu však vyhazuje výjimku
ConfigurationErrorsException: Unrecognized attribute ‚securityTrimmingEnabled‘. Note that attribute names are case-sensitive.
Když jsem bádal v kódu XmlSiteMapProvideru, tak tam je tento atribut přímo zakázaný a zřejmě se jedná o nějaký přežitek z beta-verzí.
Element <siteMapNode /> má ještě atribut roles=“…“, kam lze explicitně nastavit, jakým uživatelským rolím se má node zobrazovat. Pokud však máme dobře nastavené samotné <authorization />, pak to mnohdy nepotřebujeme. Pokud ho přesto nastavíme, pak se vyhodnocuje MÍSTO standardních přístupových práv, nikoliv jako průnik.
Atribut roles=“*“ (nebo podobně) se nám bude hodit u externích odkazů, jejichž autorizaci nelze jinak vyhodnotit a bez explicitní volby roles se nám odkaz vůbec nezobrazí.
Dále je potřeba si uvědomit, že SiteMapProvider vyhodnocuje přístupová práva od rootu sitemap dolů a pokud nevyhoví nadřazená položka, ustřelí se celý podstrom. Například je tedy problematické bez dalšího použít prázdný atribut url=““, protože jeho přístupová práva není jak vyhodnotit a příslušný podstrom se tak nezobrazí – naopak je však možné do url dávat cestu k neexistujícím stránkám, vyhodnocení se provede, jako by existovali. Pokud potřebujeme udělat siteNode bez odkazu, pak musíme použít atribut roles=“…“, aby bylo přístupová práva jak vyhodnotit.
Související články
- Lokalizace snadno a rychle – explicitní lokalizace
- Lokalizace skinů (Themes)