1

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

2 に答える 2

0

の設計によりSiteMapProviderIsAccessibleToUser常に呼び出されます。呼び出さない場合は、前の呼び出しの結果をキャッシュする必要があります。あなたのSiteMapProvider場合、結果をキャッシュすることが正しいかどうかを判断できません。それはあなたの決断です。必要なキャッシュは、実装内にある必要があります。

Active Directory からデータを取得している機能はあると思いますSecurityHelpler2().GetRolesForUser

この関数の呼び出しは非常に遅くなります。キャッシュから取得する残りのコードは、非常に高速である必要があります。

キャッシュは 1 時間しか有効でないため、1 時間ごとにユーザーが 1 回ヒットするのは非常に遅くなります。

サイトのユーザーを既に知っている場合 (そしてその数はそれほど多くありません)、速度を上げるCacheために、すべてのユーザーに対して を事前にロードすることができます。アクティブなユーザーの場合は、スライド式の有効期限の方が適しています。そうすれば、ユーザーはアクティブになるまで同じ役割を持つことになります。次回のログオン時に、新しい役割が Active Directory から読み込まれます。

于 2012-09-21T10:11:22.837 に答える