Inquiridor
Sistema lento ao autenticar pelo Active Directory

Pergunta
-
Boa tarde pessoal.
Tenho um sistema de dashboard que usa login do AD e está muito lento ao efetuar login no primeiro login.
Depois que loga o sistema fica rápido.
Se eu trabalhar com o login padrão do Membership provider, o sistema irá ficar rápido.
Acredito que ao logar, o sistema deve estar consultando o banco do AD inteiro.
Alguém sabe como devo proceder?
Grato.
Todas as Respostas
-
Olá,
Em geral a consulta ao AD não é muito performática.
Veja a seguinte classe para consultas no AD ela tem me atendido bem:
public class LdapAuthentication
{
public string LdapPath { get; set; }
public string FilterAtribute { get; set; }
/// <summary>
/// Construtor para receber o caminho Ldap
/// </summary>
/// <param name="ldapPath">Caminho LDAP do AD</param>
public LdapAuthentication(string ldapPath)
{
this.LdapPath = ldapPath;
}
/// <summary>
/// Verificar se usuário está autenticado ou pode ser autenticado no AD segundo o caminho LDAP fornecido na propriedade <paramref name="LdapPath"/>.
/// </summary>
/// <param name="domain">Domínio</param>
/// <param name="username">Login do usuário</param>
/// <param name="pwd">Password do usuário</param>
/// <returns>Verdadeiro se usuário for autenticável.</returns>
public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + @"\" + username;
DirectoryEntry entry = new DirectoryEntry(LdapPath, domainAndUsername, pwd);
try
{
// Bind to the native AdsObject to force authentication.
//Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
// Update the new path to the user in the directory
LdapPath = result.Path;
FilterAtribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception("Erro na autenticação do usuário. Descrição: " + ex.Message);
}
return true;
}
/// <summary>
/// Buscar os grupos que o usuário é menbro
/// </summary>
/// <returns></returns>
public string GetGroups()
{
DirectorySearcher search = new DirectorySearcher(LdapPath);
search.Filter = "(cn=" + FilterAtribute + ")";
search.PropertiesToLoad.Add("memberOf");
StringBuilder groupNames = new StringBuilder();
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
String dn;
int equalsIndex, commaIndex;
for (int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
dn = (String)result.Properties["memberOf"][propertyCounter];
equalsIndex = dn.IndexOf("=", 1, System.StringComparison.Ordinal);
commaIndex = dn.IndexOf(",", 1, System.StringComparison.Ordinal);
if (-1 == equalsIndex)
{
return null;
}
groupNames.Append(dn.Substring((equalsIndex + 1),
(commaIndex - equalsIndex) - 1));
groupNames.Append("|");
}
}
catch (Exception ex)
{
throw new Exception("Erro ao obter os grupos do usuário. Descrição: " + ex.Message);
}
return groupNames.ToString();
}
/// <summary>
/// Buscar o e-mail do usuário configurado no Active Directory.
/// </summary>
/// <param name="domain">Domínio</param>
/// <param name="username">Login do usuário</param>
/// <param name="pwd">Password do usuário</param>
/// <returns>E-mail do usuário</returns>
public string GetUserEmail(string domain, string username, string pwd)
{
string email = string.Empty;
string domainAndUsername = domain + @"\" + username;
DirectoryEntry directoryEntry = new DirectoryEntry(LdapPath, domainAndUsername, pwd);
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = String.Format("(&(objectClass=user)(SAMAccountName=*{0}*))", username);
SearchResultCollection searchResults = directorySearcher.FindAll();
try
{
if (searchResults.Count > 0 && searchResults[0].Properties["mail"][0] != null)
email = searchResults[0].Properties["mail"][0].ToString();
}
catch
{
//Se não encontrar e-mail vai gerar erro.
}
return email;
}
/// <summary>
/// Buscar o display name (nome completo) do usuário no Active Directory.
/// </summary>
/// <param name="domain">Domínio</param>
/// <param name="username">Login do usuário</param>
/// <param name="pwd">Password do usuário</param>
/// <returns>Nome do usuário</returns>
public string GetUserDisplayName(string domain, string username, string pwd)
{
string displayName = string.Empty;
string domainAndUsername = domain + @"\" + username;
DirectoryEntry directoryEntry = new DirectoryEntry(LdapPath, domainAndUsername, pwd);
DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry);
directorySearcher.Filter = String.Format("(&(objectClass=user)(SAMAccountName=*{0}*))", username);
SearchResultCollection searchResults = directorySearcher.FindAll();
try
{
if (searchResults.Count > 0 && searchResults[0].Properties["mail"][0] != null)
displayName = searchResults[0].Properties["displayName"][0].ToString();
}
catch (Exception)
{
}
return displayName;
}
/// <summary>
/// Buscar todos os grupos que usuário pertence mesmo quando o grupo estiver dentro de outros grupos (recursivo).
/// </summary>
/// <param name="userDn">Path do AD com atributo DN do usuário</param>
/// <param name="recursive">Se deve ser recursivo (grupos dentro de grupos)</param>
/// <returns>Lista de todos os grupos do usuário</returns>
public ArrayList GroupsRecursive(string userDn, bool recursive)
{
ArrayList groupMemberships = new ArrayList();
var groupsNested = AttributeValuesMultiString("memberOf", userDn, groupMemberships, recursive);
var arrayGroups = new ArrayList();
foreach (string groupName in groupsNested)
{
string[] groupsSplit = groupName.Replace(",", "=").Split('=');
arrayGroups.Add(groupsSplit[1]);
}
return arrayGroups;
}
/// <summary>
/// Buscar os atributos para possível conexão e pesquisa em grupos do Active Directory.
/// </summary>
/// <param name="attributeName">Nome do atributo</param>
/// <param name="objectDn">Objeto Dn</param>
/// <param name="valuesCollection">Array</param>
/// <param name="recursive">Se deve ser recursivo</param>
/// <returns>Lista de atributos</returns>
private ArrayList AttributeValuesMultiString(string attributeName, string objectDn,
ArrayList valuesCollection, bool recursive)
{
DirectoryEntry ent = new DirectoryEntry(objectDn);
PropertyValueCollection propertyValueCollection = ent.Properties[attributeName];
IEnumerator en = propertyValueCollection.GetEnumerator();
while (en.MoveNext())
{
if (en.Current != null)
{
if (!valuesCollection.Contains(en.Current.ToString()))
{
valuesCollection.Add(en.Current.ToString());
if (recursive)
{
AttributeValuesMultiString(attributeName, "LDAP://" + en.Current, valuesCollection, true);
}
}
}
}
ent.Close();
ent.Dispose();
return valuesCollection;
}
}Att
_______________________________________________________________________________________________________________________Luciano Rieth
-
Obrigado Luciano.
Me parece que isso irá me ajudar, mas me tira uma duvida por favor.
É que eu não tenho muita experiência, mas estou aprendendo.
Eu devo criar uma classe (Botão direito, criar arquivo LDap.cs e etc)?
Qual são as namespaces que eu vou precisar além de:using System.Web.Security; using System.Security.Permissions;
Grato.