![](/img/trans.png)
[英]How to add and access additional properties once logged in using Azure Active Directory in MVC?
[英]Trying to access Properties in Active Directory to add to a Database
根据输入的 ID 从 AD 中提取用户信息。 我得到的错误是:
无法将类型“字符串”隐式转换为类型“System.DirectoryServices.DirectoryEntry”
发生在Save
方法中:
DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID);
打开连接:
private DirectoryEntry GetDirectoryObject()
{
DirectoryEntry oDE;
oDE = new DirectoryEntry("LDAP://myConnection");
return oDE;
}
查询广告:
public string QueryAD(string userNID)
{
DirectorySearcher ds = new DirectorySearcher
{
SearchRoot = new DirectoryEntry(""),
//start searching from local domain
Filter = userNID
};
ds.PropertiesToLoad.Add("givenname");
ds.PropertiesToLoad.Add("sn");
ds.PropertiesToLoad.Add("mail");
// start searching
SearchResultCollection searchCollection = ds.FindAll();
try
{
foreach (SearchResult result in searchCollection)
{
if (result.Properties.PropertyNames != null)
foreach (string propKey in result.Properties.PropertyNames)
{
// Display each of the values for the property identified by the property name.
foreach (object prop in result.Properties[propKey])
{
if ((propKey == "userPrincipalName"))
{
return prop.ToString();
}
}
}
return "Unknown User";
}
catch (Exception ex)
{
return "Unknown User";
}
}
保存新用户:
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID);
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = GIVENNAME GOES HERE,
LASTNAME = SURNAME GOES HERE,
EMAIL = MAIL GOES HERE,
ACTIVE = true/*Convert.ToBoolean(objSearchRolesViewModel.ActiveStatus)*/,
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
我需要能够从 Active Directory 访问属性并将它们添加到添加新用户时发送到数据库的内容中。
在您的代码中, QueryAD(objSearchRolesViewModel.NID);
返回一个字符串,但您将其分配给 DirectoryEntity。 这行不通。
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
DirectoryEntry de = new DirectoryEntry();
de = QueryAD(objSearchRolesViewModel.NID); // <--- This is the issue.
...
从 QueryAD 函数查找 DirectoryEntry 并返回该对象以使您的调用工作。
public string QueryAD(string userNID) // You will need to return DirectoryEntry to make your code work.
{
DirectorySearcher ds = new DirectorySearcher
编辑:
我发现将 UserPrincipal 与 PrincipalContext 一起使用要简单得多。 使用您的域名查找 PrincipalContext 并在未使用域帐户运行时提供凭据。 然后,简单地通过 SamAccountName、Name/ID 或 DistinguishedName 查找用户。
您将需要'System.DirectoryServices.AccountManagement'
nuget 包以供主体使用。
public static UserPrincipal QueryAD(string UserName)
{
PrincipalContext context = new PrincipalContext(ContextType.Domain, "Aeth", "user", "password");
// Without creds if the account running the code is already a domain account
//PrincipalContext context = new PrincipalContext(ContextType.Domain, "Aeth");
// You can search the account by SamAccountName, DistinguishedName, UserPrincipalName or SID
return UserPrincipal.FindByIdentity(context, IdentityType.Name, UserName);
}
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
UserPrincipal user = QueryAD(objSearchRolesViewModel.User_Id);
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = user.GivenName, // Get FirstName
LASTNAME = user.Surname, // Get LastName
EMAIL = user.EmailAddress, // Get Email Address
ACTIVE = user.Enabled, // Get User Status
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
以下是使用 DirectoryEntry 方法的代码。 如果您使用无权访问 AD 的帐户运行此代码,请确保添加凭据。
搜索广告的方法
public DirectoryEntry QueryAD(string UserName)
{
try
{
DirectorySearcher ds = new DirectorySearcher
{
SearchRoot = new DirectoryEntry(),
//start searching from local domain
Filter = "(&" +
"(objectClass=user)" +
"(name=" + UserName + "))" // This is Username
};
// start searching
return ds.FindOne().GetDirectoryEntry();
}
catch (Exception ex)
{
throw new ApplicationException("error occured while querying AD");
}
}
检查帐户是否处于活动状态的方法
private bool IsActive(DirectoryEntry de)
{
if (de.NativeGuid == null) return false;
int flags = (int)de.Properties["userAccountControl"].Value;
return !Convert.ToBoolean(flags & 0x0002);
}
将用户保存到数据库的方法
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
DirectoryEntry userEntry = QueryAD(objSearchRolesViewModel.User_Id);
if (userEntry == null)
{
//Handle error where No User was Found.
throw new ApplicationException("User Not Found");
}
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = userEntry.Properties["givenname"].Value.ToString(),
LASTNAME = userEntry.Properties["sn"].Value.ToString(),
EMAIL = userEntry.Properties["mail"].Value.ToString(),
ACTIVE = IsActive(userEntry),
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
一些挑剔的事情:
打开连接
创建DirectoryEntry
对象实际上并没有打开任何连接。 这就是几乎所有 Microsoft 库的工作方式:构造函数不发出任何 I/O 请求。 第一个网络请求是在您第一次开始使用该对象时发出的。
此外, new DirectoryEntry("")
与new DirectoryEntry()
new DirectoryEntry("")
具有完全相同的效果 - 空字符串不会给你任何东西。 而且,如果您不设置SearchRoot
属性,它无论如何都会自动将其设置为当前域。 所以你甚至不需要设置它,除非你需要将它设置到不同的域或 OU。
现在来回答这个问题:
您已经得到了几个答案,但它们并不理想。 如果需要,您当然可以使用System.DirectoryServices.AccountManagement
命名空间,它只是System.DirectoryServices
的包装器,使事情变得更容易。 但就像所有让事情变得更容易的事情一样,它是以牺牲性能为代价的。 与您自己直接使用System.DirectoryServices
,它的性能总是更差。 一个原因是因为每当创建UserPrincipal
对象时,它都会检索具有帐户值的每个属性。 您可能没有使用每个属性。
如果您可以自己使用DirectoryEntry
/ DirectorySearcher
,您将拥有更好的代码性能。
Jawad 的答案也适用,但它有一个关键问题会减慢您的代码速度: DirectorySearcher
将返回您请求的所有属性。 您已经设置了PropertiesToLoad
,这很好 - 它会将结果限制为仅您需要的属性。 但是,如果您使用GetDirectoryEntry()
,该信息将丢失。 如果您随后开始在DirectoryEntry
上使用.Properties
,它将发出一个新的网络请求并请求所有具有值的属性。 除了您可以避免的第二个网络请求之外,这可能是您没有使用的大量数据。
我建议只从QueryAD
返回一个SearchResult
,这样您就可以使用搜索中返回的数据。
您也可以使用FindOne()
而不是FindAll()
,因为无论如何您都只使用第一个结果。 这将使 AD 在找到一个结果后停止查找。 如果未找到用户,只需测试null
。
public SearchResult QueryAD(string userNID)
{
DirectorySearcher ds = new DirectorySearcher(userNID) {
PropertiesToLoad = {"givenname", "sn", "mail"}
};
return ds.FindOne();
}
public void SaveUser(SearchRolesViewModel objSearchRolesViewModel, string userID)
{
var result = QueryAD(objSearchRolesViewModel.NID);
if (result == null)
{
//user wasn't found!
}
USERACCOUNT objUserAccount = new USERACCOUNT
{
HPID = Convert.ToInt32(objSearchRolesViewModel.NewUserHealthPlans),
DOMAIN = "Aeth",
NTUSERID = objSearchRolesViewModel.User_Id,
ROLEID = Convert.ToInt32(objSearchRolesViewModel.UserRole),
FIRSTNAME = (string) result.Properties["givenName"]?[0],
LASTNAME = (string) result.Properties["sn"]?[0],
EMAIL = (string) result.Properties["mail"]?[0],
ACTIVE = true/*Convert.ToBoolean(objSearchRolesViewModel.ActiveStatus)*/,
DEFAULTPLANID = Convert.ToInt32(objSearchRolesViewModel.NewUserPrimaryHealthPlan),
CREATEID = userID,
CREATEDATE = DateTime.Now,
UPDATEID = userID,
UPDATEDATE = DateTime.Now
};
_context.USERACCOUNTs.Add(objUserAccount);
_context.SaveChanges();
}
SearchResult
的Properties
将始终以数组的形式呈现属性,即使它们是 AD 中的单值属性。 这与DirectoryEntry
不同。 但是,这是对的原因[0]
在result.Properties["givenName"]?[0] as string
。 ?
是测试null
,因为如果属性没有在 AD 中设置,那么它根本不会出现在Properties
集合中。
我写了一篇关于在使用 AD 编程时获得更好性能的文章,重点是 C#。 你可能会喜欢阅读它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.