Низкая производительность с WindowsTokenRoleProvider
Я использую WindowsTokenRoleProvide
r для определения членства в группе Active Directory в веб-приложении ASP.NET.
Моя проблема в том, что производительность не очень хорошая, особенно когда пользователь во многих группах. Как пример, я в 253(!) Группах, и WindowsTokenRoleProvider
занимает около 150 секунд, чтобы определить, в каких группах я нахожусь.
Я знаю, что могу использовать кеширование, чтобы это не делалось при последующих запросах пользователя, но, очевидно, недопустимо долго ждать первого попадания.
Какие у меня варианты? Могу ли я заставить WindowsTokenRoleProvider
рассматривать только определенные группы? (Меня интересует только 5).
1 ответ
Некоторое тестирование показало, что моя проблема заключается в том, что вызов:
Roles.IsUserInRole(groupName)
получает доступ к методу GetRolesForUser
в RoleProvider
- который извлекает детали каждой роли, членом которой является пользователь.
Но звонит:
Roles.Provider.IsUserInRole(groupName)
определяет, находится ли пользователь в группе - без получения сведений о каждой роли, в которой он находится.
Странно, но это похоже на использование Roles.Provider.IsUserInRole
решит мою проблему.
* ОБНОВИТЬ *
Оказывается, это лишь частичный обходной путь; если я использую обязательные проверки разрешений или "разрешить" и "запретить" в web.comfig, то WindowsTokenRoleProvider
все еще идет и медленно получает детали каждой группы, членом которой является пользователь: o (
Так что мой вопрос все еще стоит...
* ОБНОВИТЬ *
Я решил это, создав класс, который выходит из WindowsTokenRoleProvider и переопределил GetRolesForUser
поэтому он проверяет только членство ролей, указанных в конфигурации. Также включает кеширование:
/// <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)
{
// Will 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 = String.Concat(username, ":", base.ApplicationName);
// 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[]);
}
// Was the list of roles for the user in the cache?
if (roles == null)
{
roles = new List<string>();
// For each system role, determine if the user is a member of that role
foreach (SystemRoleElement role in WebConfigSection.Settings.SystemRoles)
{
if (base.IsUserInRole(username, role.Name))
{
roles.Add(role.Name);
}
}
// 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();
}