ASP.NET Web サイトで securityTrimming を使用し、サイト マップを使用してメニューを表示/非表示にしています。しかし、問題は、すべてのポストバックがこのクラスに到達し続け、IsAccessibleToUser メソッドを通過することです。
Active Directory グループを使用しているため、実際にはパフォーマンスの問題です。(ADからグループを取得するときに最初の呼び出しが行われたときに、すでにグループ(ユーザーが属している)をキャッシュしていますが、このメソッドの実行にはまだ時間がかかります.
このメソッドのパフォーマンスを改善するための他の方法、またはポストバックごとにこのメソッドを呼び出さない方法を誰かが提案してくれれば、それは素晴らしいことです。現在、私が理解しているように、このメソッドはサイトマップとメニューから自動的に実行されます。
Web.config:
<siteMap defaultProvider="CustomSiteMapProvider" enabled="true">
<providers>
<clear/>
<add siteMapFile="Web.sitemap" name="CustomSiteMapProvider" type="xxx.CustomSiteMapProvider"
description="Default SiteMap provider." securityTrimmingEnabled="true"/>
</providers>
</siteMap>
クラスファイル..
public class CustomSiteMapProvider : System.Web.XmlSiteMapProvider
{
public override bool IsAccessibleToUser(System.Web.HttpContext context, System.Web.SiteMapNode node)
{
// return true false depend on user has access to menu or not.
// return UserIsInRole(string role, string userName);
}
}
これが、AD からロールを取得してキャッシュする方法です。(このコードのベースは別の記事から入手しました)
public class SecurityHelpler2 : WindowsTokenRoleProvider
{
/// <summary>
/// Retrieve the list of roles (Windows Groups) that a user is a member of
/// </summary>
/// <remarks>
/// Note that we are checking only against each system role because calling:
/// base.GetRolesForUser(username);
/// Is very slow if the user is in a lot of AD groups
/// </remarks>
/// <param name="username">The user to check membership for</param>
/// <returns>String array containing the names of the roles the user is a member of</returns>
public override string[] GetRolesForUser(string username)
{
// contain the list of roles that the user is a member of
List<string> roles = null;
// Create unique cache key for the user
string key = username.RemoveBackSlash();
// Get cache for current session
Cache cache = HttpContext.Current.Cache;
// Obtain cached roles for the user
if (cache[key] != null)
{
roles = new List<string>(cache[key] as string[]);
}
// is the list of roles for the user in the cache?
if (roles == null)
{
// create list for roles
roles = new List<string>();
Dictionary<string, string> groupNames = new Dictionary<string, string>();
// check the groups are available in cache
if (cache[Common.XXX_SEC_GROUPS] != null)
{
groupNames = new Dictionary<string, string>(cache[Common.XXX_SEC_GROUPS] as Dictionary<string, string>);
}
else
{
// if groups are not available in the cache get again
// here we are getting the valid group from web config
// also add to the cache inside this method
groupNames = Utility.GetRetailSecurityGroups();
}
// For each role, determine if the user is a member of that role
foreach (KeyValuePair<String,String> entry in groupNames)
{
if (base.IsUserInRole(username, entry.Value))
{
roles.Add(entry.Value);
}
}
// Cache the roles for 1 hour
cache.Insert(key, roles.ToArray(), null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
}
// Return list of roles for the user
return roles.ToArray();
}
}
}
最後に、IsAccessibleToUser メソッドから次のメソッドを呼び出します。
/// <summary>
/// Get the usr role from the cache and check the role exists
/// </summary>
/// <param name="role"></param>
/// <param name="userName"></param>
/// <returns>return true if the user is in role</returns>
public static bool UserIsInRole(string role, string userName)
{
// contains the list of roles that the user is a member of
List<string> roles = null;
// Get cache for current session
Cache cache = HttpContext.Current.Cache;
string key = userName.RemoveBackSlash();
// Obtain cached roles for the user
if (cache[key] != null)
{
roles = new List<string>(cache[key] as string[]);
}
else
{
// if the cache is null call the method and get the roles.
roles = new List<string>(new SecurityHelpler2().GetRolesForUser(userName) as string[]);
}
if (roles.Count > 0)
{
return roles.Contains(role);
}
return false;
}