【问题标题】:How to get current Azure Active Directory (AAD) user email from Windows 10如何从 Windows 10 获取当前 Azure Active Directory (AAD) 用户电子邮件
【发布时间】:2021-06-10 21:34:23
【问题描述】:

我需要能够通过 C# 从 Windows 10 检索当前登录的 Azure AD 用户的电子邮件(技术上是 UPN)。我可以得到以下信息:

WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent();

string userSid =
    currentIdentity.Claims.FirstOrDefault(
        u => u.Type == System.Security.Claims.ClaimTypes.PrimarySid).Value;

string username = currentIdentity.Name; // This returns "AzureAD\\TestUser"

但我真正需要的是如下电子邮件/UPN (test.user@testtenant.onmicrosoft.com):

我查看了currentIdentity 对象的所有属性,但在任何地方都看不到它,这可能吗?

【问题讨论】:

  • @PamelaPeng 我在发布后不久就注意到了这个问题,但是它抛出了一个InvalidCastException 并带有错误消息Unable to cast object of type 'System.DirectoryServices.AccountManagement.GroupPrincipal' to type 'System.DirectoryServices.AccountManagement.UserPrincipal'.

标签: c# windows azure azure-active-directory


【解决方案1】:

因为有问题的计算机是 Azure 注册的,它不会被视为在域(即本地网络域)上,因此任何涉及连接到 PrincipalContext 的操作都会失败。用户的UPN也没有存储在WindowsIdentity对象中,大概是为了安全吧?

它可以从secur32.dll 中的GetUserNameEx 方法中检索到,使用如下所示:

public enum ExtendedFormat
{
    NameUnknown = 0,
    NameFullyQualifiedDN = 1,
    NameSamCompatible = 2,
    NameDisplay = 3,
    NameUniqueId = 6,
    NameCanonical = 7,
    NameUserPrincipal = 8,
    NameCanonicalEx = 9,
    NameServicePrincipal = 10,
    NameDnsDomain = 12,
}

[DllImport("secur32.dll", CharSet = CharSet.Unicode)]
public static extern int GetUserNameEx(int nameFormat, StringBuilder userName, ref int userNameSize);

public string GetCurrentUPN()
{
    StringBuilder userUPN = new StringBuilder(1024);
    int userUPNSize = userUPN.Capacity;

    if (GetUserNameEx((int)ExtendedFormat.NameUserPrincipal, userUPN, ref userUPNSize) != 0)
    {
        return userUPN.ToString();
    }

    return null;
}

这显然仅适用于当前用户,大概是为了检索另一个用户的 UPN,您需要使用 Graph API 直接联系 Azure AD 租户。

【讨论】:

    【解决方案2】:

    你必须使用 System.Security.Claims.ClaimTypes.Upn

    这会给你 test.user@testtenant.onmicrosoft.com

    【讨论】:

    • 我检查了返回对象的所有声明,但 UPN 不在那里,只有 SID 和一些其他标识符,这些标识符似乎是用户所属的组。
    • 您是否使用了正确的命名空间?我已经在我的代码中使用了它,并且还可以在 MS 文档中看到 docs.microsoft.com/en-us/dotnet/api/…
    • 我检查了返回的对象所包含的每个声明,连同声明值,UPN 根本不存在。您所指的ClaimType 只是一个用于帮助清理代码的字符串常量库,对象的声明字典中的实际值是http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn。所以不,这个声明不在 WindowsIdentity 对象中。
    【解决方案3】:

    如果您使用 .NET 3.5 及更高版本,则可以使用 UserPrincipal.Current 属性:

    // set up domain context
    PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
    
    // find current user
    UserPrincipal user = UserPrincipal.Current;
    
    if(user != null)
    {
       string loginName = user.SamAccountName; // or whatever you mean by "login name"
    }    
    

    InvalidCastException 也有类似问题:https://stackoverflow.com/a/31819930/13308381

    【讨论】:

    • new PrincipalContext(ContextType.Domain) 抛出带有内部 LdapExceptionPrincipalServerDownException 并带有错误消息 The LDAP server is unavailable.UserPrincipal.Current 抛出 InvalidCastException 带有错误消息 Unable to cast object of type 'System.DirectoryServices.AccountManagement.GroupPrincipal' to type 'System.DirectoryServices.AccountManagement.UserPrincipal'.
    猜你喜欢
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-23
    • 1970-01-01
    相关资源
    最近更新 更多