You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无需用户认证编程获取AAD租户ID/域名以查询用户UPN

解决AAD加入设备上获取用户UPN的问题

我完全理解你在AAD加入的设备上调用UserPrincipal.FindByIdentity时遇到的困境——那个PrincipalServerDownException确实是因为AAD加入的设备并没有绑定传统的Active Directory域,直接用ContextType.Domain创建PrincipalContext自然找不到LDAP服务器。下面给你几个实用的解决思路,帮你顺利拿到用户的UPN:

1. 最直接的方式:从WindowsIdentity的声明中读取UPN

你之前误以为WindowsIdentity.Name不是UPN就放弃了这个方向,但其实Windows身份令牌里已经包含了UPN的声明信息,直接读取它就行,根本不用碰AD相关的API。代码示例:

public string GetUpnForLoggedOnUser()
{
    var windowsIdentity = WindowsIdentity.GetCurrent();
    // 查找UPN对应的声明
    var upnClaim = windowsIdentity.Claims
        .FirstOrDefault(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn");
    
    return upnClaim?.Value ?? "无法获取UPN";
}

这个方法在AAD加入设备和域加入设备上都能正常工作,而且不需要依赖任何AD服务器连接,是最可靠的方案。

2. 如果一定要用UserPrincipal的方案

如果你坚持要使用UserPrincipal类,那首先得明确AAD租户的域名,然后用它来初始化PrincipalContext。获取租户信息的方式有两种:

  • 从注册表读取:AAD加入的设备会在注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\CDJ\TenantInfo下存储租户的详细信息,包括TenantId和TenantName(通常是xxx.onmicrosoft.com格式)。
  • 通过系统API获取:可以使用Windows.System.UserProfile.UserInformation.GetPrincipalNameAsync()(需要在UWP或桌面应用中启用对应的权限)。

拿到租户域名后,修改你的代码如下:

public string GetUpnForLoggedOnUser()
{
    var windowsIdentity = WindowsIdentity.GetCurrent();
    // 假设你已经通过注册表或其他方式拿到了租户域名
    string tenantDomain = "your-tenant-name.onmicrosoft.com";

    using (var principalContext = new PrincipalContext(ContextType.Domain, tenantDomain))
    {
        // 明确指定用UPN来查找用户,避免格式歧义
        var userPrincipal = UserPrincipal.FindByIdentity(
            principalContext, 
            IdentityType.UserPrincipalName, 
            windowsIdentity.Name);
        
        return userPrincipal?.UserPrincipalName ?? "无法获取UPN";
    }
}

不过要注意,这种方式需要设备能访问AAD的LDAP服务,而且你得确保租户域名的正确性,相比第一种方案要麻烦一些。

为什么你的原有代码会报错?

简单解释下你遇到的问题根源:

  • 域加入的设备会自动绑定本地AD域,无参数的PrincipalContext(ContextType.Domain)会自动连接到域控制器的LDAP服务器,所以能正常工作。
  • 但AAD加入的设备并没有本地域的绑定,也没有可用的LDAP服务器,所以会抛出LDAP server is unavailable的异常。
  • 另外WindowsIdentity.Name的格式是DOMAIN\Username,并不是UPN,用它来查找UserPrincipal本身就容易出错。

内容的提问来源于stack exchange,提问作者Martin K

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:07:53