You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C++本地Windows服务访问Azure托管ASP.NET Core 3.1 Web API的Azure AD认证方案咨询

针对你的C++ Windows服务访问Azure AD保护API的解决方案

结合你提到的企业单租户、身份识别、租户限制这些核心需求,我整理了几个可行的方案,每个方案都对应你的具体疑问给出细节:

方案1:使用MSAL C++库实现Azure AD认证(首选)

你之前提到“无ADAL/MSAL的C库”其实是过时的信息了——微软已经推出了**正式版的MSAL C库**,专门用于C++应用集成Azure AD认证,支持交互式和非交互式场景,完美匹配你的需求。

核心优势:

  • 原生支持Azure AD的身份验证流程,能直接获取包含用户身份信息的JWT令牌(比如nameupnoid等字段)
  • 轻松实现单租户限制:在API的Azure AD应用注册中,设置“账户类型”为仅限此组织目录中的账户,自动拒绝外部租户的请求
  • 支持多种认证模式:
    • 非交互式:使用Windows集成认证(IWA)直接复用当前服务运行账户的Windows凭据,无需弹窗
    • 交互式:触发登录弹窗让用户输入凭据(适合需要用户明确授权的场景)

实现步骤:

  1. 注册客户端应用:在Azure AD中注册一个C++客户端应用,设置账户类型为单租户,添加API权限(选择你的Web API的权限,比如access_as_user
  2. 配置MSAL C++:在你的Windows服务中引入MSAL C++库,初始化客户端:
    #include "msal.h"
    auto pClient = msal::create_public_client_application("你的客户端应用ID", "https://login.microsoftonline.com/你的租户ID");
    
  3. 获取访问令牌
    • 非交互式(Windows凭据):
      auto result = pClient->acquire_token_silent({"api://你的API应用ID/access_as_user"}, msal::account{});
      if (result.status() != msal::result_status::success) {
          // 静默失败,尝试IWA模式
          result = pClient->acquire_token_by_integrated_windows_authentication({"api://你的API应用ID/access_as_user"});
      }
      
    • 交互式:
      auto result = pClient->acquire_token_interactive({"api://你的API应用ID/access_as_user"});
      
  4. API验证令牌:在ASP.NET Core API中配置Azure AD认证,自动验证JWT令牌的租户ID、签名和权限,同时可以从HttpContext.User中获取用户的身份信息(比如User.FindFirst(ClaimTypes.NameIdentifier)?.Value获取用户ID)

方案2:客户端证书认证(适合纯非交互式服务)

如果你的服务完全不需要用户交互,客户端证书认证是一个可靠的选择。虽然你担心“无法识别身份”,但通过预先绑定证书与Azure AD用户的关系,也能实现身份识别,同时轻松限制租户访问。

核心优势:

  • 纯非交互式,无需用户输入
  • 租户限制:可以在API的认证策略中,只允许由本租户CA颁发的证书,或者验证证书的主题字段包含租户标识
  • 身份识别:将证书的Thumbprint或Subject与Azure AD用户的扩展属性绑定,API收到请求后通过证书信息查找对应的用户

实现步骤:

  1. 准备客户端证书:生成或使用企业CA颁发的证书,确保证书的Subject或SAN包含可识别的信息(比如用户UPN)
  2. 绑定证书与Azure AD用户:在Azure AD中,将证书的Thumbprint添加到用户的extensionAttributes中,或者使用自定义属性存储证书信息
  3. 配置API的证书认证:在ASP.NET Core API中启用客户端证书认证,并添加验证逻辑:
    services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
        .AddCertificate(options => {
            options.AllowedCertificateTypes = CertificateTypes.All;
            options.Events = new CertificateAuthenticationEvents {
                OnCertificateValidated = context => {
                    // 验证证书是否属于本租户:检查颁发者是否为企业CA
                    if (!context.ClientCertificate.Issuer.Contains("你的租户域名")) {
                        context.Fail("Invalid issuer");
                        return Task.CompletedTask;
                    }
                    // 根据证书Thumbprint查找Azure AD用户
                    var user = _userManager.FindByThumbprint(context.ClientCertificate.Thumbprint);
                    if (user == null) {
                        context.Fail("User not found");
                        return Task.CompletedTask;
                    }
                    // 将用户信息添加到HttpContext.User
                    context.Principal = new ClaimsPrincipal(new ClaimsIdentity(new[] {
                        new Claim(ClaimTypes.NameIdentifier, user.Id),
                        new Claim(ClaimTypes.Name, user.DisplayName)
                    }, CertificateAuthenticationDefaults.AuthenticationScheme));
                    context.Success();
                    return Task.CompletedTask;
                }
            };
        });
    
  4. C++服务发送请求:使用WinHTTP或CURL加载客户端证书,发送HTTPS请求到API:
    // WinHTTP示例:加载证书
    HINTERNET hSession = WinHttpOpen(L"C++ Service", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
    HINTERNET hConnect = WinHttpConnect(hSession, L"你的API域名", INTERNET_DEFAULT_HTTPS_PORT, 0);
    HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/api/resource", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
    // 添加客户端证书
    WinHttpSetOption(hRequest, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, (LPVOID)&certContext, sizeof(CERT_CONTEXT));
    

方案3:Windows集成认证(Kerberos/NTLM)+ Azure AD Hybrid

如果你的企业已经将本地AD同步到Azure AD(Hybrid身份),可以直接使用Windows凭据进行认证,无需额外的Azure AD令牌流程,非常适合内部服务场景。

核心优势:

  • 完全复用用户的Windows凭据,无需登录弹窗或额外配置
  • 身份识别:API可以直接获取用户的AD身份信息(UPN、SID),并验证是否属于本租户
  • 租户限制:通过AD组或Azure AD组限制API访问权限

实现步骤:

  1. API启用Windows认证:在ASP.NET Core API中配置Windows认证:
    // IIS托管场景
    services.AddAuthentication(IISDefaults.AuthenticationScheme);
    // 自托管场景
    services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
    
  2. 同步AD用户到Azure AD:确保本地AD用户已经通过Azure AD Connect同步到Azure AD,这样API可以通过User.FindFirst(ClaimTypes.Upn)获取用户的UPN,验证是否属于本租户
  3. C++服务发送请求:使用WinHTTP自动使用当前服务账户的Windows凭据,或者指定用户凭据:
    // WinHTTP示例:使用当前用户凭据
    WinHttpSetOption(hRequest, WINHTTP_OPTION_AUTH_TARGET, (LPVOID)WINHTTP_AUTH_TARGET_SERVER, sizeof(DWORD));
    DWORD dwAuthScheme = WINHTTP_AUTH_SCHEME_NTLM | WINHTTP_AUTH_SCHEME_NEGOTIATE;
    WinHttpSetOption(hRequest, WINHTTP_OPTION_ENABLE_SSL, (LPVOID)&dwAuthScheme, sizeof(DWORD));
    // 发送请求时自动使用当前凭据
    WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
    

方案对比与推荐

方案身份识别租户限制交互性适用场景
MSAL C++认证✅ 直接获取JWT中的用户信息✅ 配置应用注册即可支持交互式/非交互式首选,符合Azure AD最佳实践
客户端证书认证✅ 需要绑定证书与用户✅ 验证证书颁发者/主题纯非交互式无用户交互的后台服务
Windows集成认证✅ 获取AD用户信息✅ 通过AD/Azure AD组限制无交互企业内部Hybrid AD环境

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

火山引擎 最新活动