适用于:  员工租户(了解详细信息)
 员工租户(了解详细信息)
了解如何为调用 Web API 的守护程序应用程序配置代码。
支持守护程序应用的 Microsoft 库
以下 Microsoft 库支持守护程序应用:
              1联机服务通用许可条款适用于公共预览版中的库。
守护程序应用程序使用应用程序权限,而不是委托的权限。 因此,它们支持的帐户类型不能是任何组织目录中的帐户或任何个人 Microsoft 帐户(例如,Skype、Xbox、Outlook.com)。 没有租户管理员可以对 Microsoft 个人帐户的守护程序应用程序授予同意。 你需要选择“我的组织中的帐户”或“任何组织中的帐户”。
在应用程序配置中指定的颁发机构应该包括你的租户 ID 或者与你的组织相关联的域名。
即使在需要提供多租户工具的情况下,也应在此流中使用租户 ID 或域名,而不是  或 common,因为该服务无法可靠推断应使用哪个租户。organizations
在Microsoft身份验证库(MSAL)中,客户端凭据(机密或证书)作为机密客户端应用程序构造的参数传递。
重要
即使应用程序是作为服务运行的控制台应用程序,如果它是守护程序应用程序,则也需要是机密客户端应用程序。
 
配置文件
配置文件定义:
- 云实例和租户 ID,它们共同构成了“机构”。
- 通过应用程序注册获得的客户端 ID。
- 客户端机密或证书。
下面是关于在 appsettings.json 文件中定义配置的示例。 此示例摘自 GitHub 上的 .NET 控制台守护程序代码示例。
{
    "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "TenantId": "[Enter here the tenantID or domain name for your Azure AD tenant]",
        "ClientId": "[Enter here the ClientId for your application]",
        "ClientCredentials": [
            {
                "SourceType": "ClientSecret",
                "ClientSecret": "[Enter here a client secret for your application]"
            }
        ]
    }
}
请提供证书而不是客户端密码或工作负载联合身份验证凭据。
 private final static String CLIENT_ID = "";
 private final static String AUTHORITY = "https://login.microsoftonline.com/<tenant>/";
 private final static String CLIENT_SECRET = "";
 private final static Set<String> SCOPE = Collections.singleton("https://graph.microsoft.com/.default");
              Node.js 守护程序示例的配置参数位于 .env 文件中:
# Credentials
TENANT_ID=Enter_the_Tenant_Info_Here
CLIENT_ID=Enter_the_Application_Id_Here
// You provide either a ClientSecret or a CertificateConfiguration, or a ClientAssertion. These settings are exclusive
CLIENT_SECRET=Enter_the_Client_Secret_Here
CERTIFICATE_THUMBPRINT=Enter_the_certificate_thumbprint_Here
CERTIFICATE_PRIVATE_KEY=Enter_the_certificate_private_key_Here
CLIENT_ASSERTION=Enter_the_Assertion_String_Here
# Endpoints
// the Azure AD endpoint is the authority endpoint for token issuance
AAD_ENDPOINT=Enter_the_Cloud_Instance_Id_Here // https://login.microsoftonline.com/
// the graph endpoint is the application ID URI of Microsoft Graph
GRAPH_ENDPOINT=Enter_the_Graph_Endpoint_Here // https://graph.microsoft.com/
使用客户端机密构建机密客户端时,Python 守护程序示例中的 parameters.json 配置文件如下所示:
{
  "authority": "https://login.microsoftonline.com/<your_tenant_id>",
  "client_id": "your_client_id",
  "scope": [ "https://graph.microsoft.com/.default" ],
  "secret": "The secret generated by Azure AD during your confidential app registration",
  "endpoint": "https://graph.microsoft.com/v1.0/users"
}
使用证书构建机密客户端时,Python 守护程序示例中的 parameters.json 配置文件如下所示:
{
  "authority": "https://login.microsoftonline.com/<your_tenant_id>",
  "client_id": "your_client_id",
  "scope": [ "https://graph.microsoft.com/.default" ],
  "thumbprint": "790E... The thumbprint generated by Azure AD when you upload your public cert",
  "private_key_file": "server.pem",
  "endpoint": "https://graph.microsoft.com/v1.0/users"
}
下面是关于在 appsettings.json 文件中定义配置的示例。 此示例摘自 GitHub 上的 .NET 控制台守护程序代码示例。
{
  "Instance": "https://login.microsoftonline.com/{0}",
  "Tenant": "[Enter here the tenantID or domain name for your Azure AD tenant]",
  "ClientId": "[Enter here the ClientId for your application]",
  "ClientSecret": "[Enter here a client secret for your application]",
  "CertificateName": "[Or instead of client secret: Enter here the name of a certificate (from the user cert store) as registered with your application]"
}
请提供 ClientSecret 或 CertificateName。 这些设置是独占的。
 
实例化 MSAL 应用程序
若要实例化 MSAL 应用程序,请添加、引用或导入 MSAL 包(取决于语言)。
结构的不同取决于您使用的是客户端机密还是证书(或者作为一种高级方案,使用已签名断言)。
引用此包
在应用程序代码中引用 MSAL 包。
向应用程序添加 Microsoft.Identity.Web.TokenAcquisition NuGet 包。
或者,如果要调用 Microsoft Graph,请添加 Microsoft.Identity.Web.GraphServiceClient 包。
你的项目可能如下所示。 需要将 appsettings.json 文件复制到输出目录。
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <RootNamespace>daemon_console</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Identity.Web.GraphServiceClient" Version="2.12.2" />
  </ItemGroup>
  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>
</Project>
在 Program.cs 文件中,在代码中添加 using 指令以引用 Microsoft.Identity.Web。
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
import com.microsoft.aad.msal4j.ClientCredentialFactory;
import com.microsoft.aad.msal4j.ClientCredentialParameters;
import com.microsoft.aad.msal4j.ConfidentialClientApplication;
import com.microsoft.aad.msal4j.IAuthenticationResult;
import com.microsoft.aad.msal4j.IClientCredential;
import com.microsoft.aad.msal4j.MsalException;
import com.microsoft.aad.msal4j.SilentParameters;
在 npm install 文件所在的文件夹中,运行 package.json 来安装这些包。 然后,导入 msal-node 包:
const msal = require('@azure/msal-node');
import msal
import json
import sys
import logging
将 Microsoft.Identity.Client NuGet 包添加到应用程序,然后在代码中添加一个 using 指令以引用它。
在 MSAL.NET 中,机密客户端应用程序通过 IConfidentialClientApplication 接口表示。
using Microsoft.Identity.Client;
IConfidentialClientApplication app;
 
使用客户端机密实例化机密客户端应用程序
下面的代码用于使用客户端机密实例化机密客户端应用程序:
   class Program
    {
        static async Task Main(string[] _)
        {
            // Get the Token acquirer factory instance. By default it reads an appsettings.json
            // file if it exists in the same folder as the app (make sure that the 
            // "Copy to Output Directory" property of the appsettings.json file is "Copy if newer").
            TokenAcquirerFactory tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
            // Configure the application options to be read from the configuration
            // and add the services you need (Graph, token cache)
            IServiceCollection services = tokenAcquirerFactory.Services;
            services.AddMicrosoftGraph();
            // By default, you get an in-memory token cache.
            // For more token cache serialization options, see https://aka.ms/msal-net-token-cache-serialization
            // Resolve the dependency injection.
            var serviceProvider = tokenAcquirerFactory.Build();
            // ...
        }
    }
从 appsettings.json 读取配置:
IClientCredential credential = ClientCredentialFactory.createFromSecret(CLIENT_SECRET);
ConfidentialClientApplication cca =
        ConfidentialClientApplication
                .builder(CLIENT_ID, credential)
                .authority(AUTHORITY)
                .build();
const msalConfig = {
  auth: {
    clientId: process.env.CLIENT_ID,
    authority: process.env.AAD_ENDPOINT + process.env.TENANT_ID,
    clientSecret: process.env.CLIENT_SECRET,
  }
};
const apiConfig = {
  uri: process.env.GRAPH_ENDPOINT + 'v1.0/users',
};
const tokenRequest = {
  scopes: [process.env.GRAPH_ENDPOINT + '.default'],
};
const cca = new msal.ConfidentialClientApplication(msalConfig);
# Pass the parameters.json file as an argument to this Python script. E.g.: python your_py_file.py parameters.json
config = json.load(open(sys.argv[1]))
# Create a preferably long-lived app instance that maintains a token cache.
app = msal.ConfidentialClientApplication(
    config["client_id"], authority=config["authority"],
    client_credential=config["secret"],
    # token_cache=...  # Default cache is in memory only.
                       # You can learn how to use SerializableTokenCache from
                       # https://msal-python.rtfd.io/en/latest/#msal.SerializableTokenCache
    )
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
           .WithClientSecret(config.ClientSecret)
           .WithAuthority(new Uri(config.Authority))
           .Build();
              Authority 是云实例和租户 ID 的串联,例如 https://login.microsoftonline.com/contoso.onmicrosoft.com 或 https://login.microsoftonline.com/aaaabbbb-0000-cccc-1111-dddd2222eeee。 在配置文件部分中显示的 appsettings.json 文件中,实例和租户分别由  和 Instance 值表示。
在上一片段源自的代码示例中,Authority 是 AuthenticationConfig 类上的一个属性,其定义如下:
/// <summary>
/// URL of the authority
/// </summary>
public string Authority
{
    get
    {
        return String.Format(CultureInfo.InvariantCulture, Instance, Tenant);
    }
}
 
通过客户端证书实例化机密客户端应用程序
下面的代码用于使用证书来构建应用程序:
代码本身完全一样。 配置中介绍了证书。
获取证书有多种方式。 有关详细信息,请参阅 https://aka.ms/ms-id-web-certificates。
下面介绍了如何从 KeyVault 获取证书。 Microsoft 标识委托给 Azure 标识的 DefaultAzureCredential,并使用了托管标识(如果可用)从 KeyVault 访问证书。 你可以在本地调试你的应用程序,因为它会使用你的开发者凭据。
  "ClientCredentials": [
      {
        "SourceType": "KeyVault",
        "KeyVaultUrl": "https://yourKeyVaultUrl.vault.azure.net",
        "KeyVaultCertificateName": "NameOfYourCertificate"
      }
在 MSAL Java 中,可以通过两个生成器使用证书来实例化机密客户端应用程序:
InputStream pkcs12Certificate = ... ; /* Containing PCKS12-formatted certificate*/
string certificatePassword = ... ;    /* Contains the password to access the certificate */
IClientCredential credential = ClientCredentialFactory.createFromCertificate(pkcs12Certificate, certificatePassword);
ConfidentialClientApplication cca =
        ConfidentialClientApplication
                .builder(CLIENT_ID, credential)
                .authority(AUTHORITY)
                .build();
或
PrivateKey key = getPrivateKey(); /* RSA private key to sign the assertion */
X509Certificate publicCertificate = getPublicCertificate(); /* x509 public certificate used as a thumbprint */
IClientCredential credential = ClientCredentialFactory.createFromCertificate(key, publicCertificate);
ConfidentialClientApplication cca =
        ConfidentialClientApplication
                .builder(CLIENT_ID, credential)
                .authority(AUTHORITY)
                .build();
const config = {
    auth: {
        clientId: process.env.CLIENT_ID,
        authority: process.env.AAD_ENDPOINT + process.env.TENANT_ID,
        clientCertificate: {
            thumbprint:  process.env.CERTIFICATE_THUMBPRINT, // a 40-digit hexadecimal string
            privateKey:  process.env.CERTIFICATE_PRIVATE_KEY,
        }
    }
};
// Create an MSAL application object
const cca = new msal.ConfidentialClientApplication(config);
有关详细信息,请参阅将证书凭据用于 MSAL 节点。
# Pass the parameters.json file as an argument to this Python script. E.g.: python your_py_file.py parameters.json
config = json.load(open(sys.argv[1]))
# Create a preferably long-lived app instance that maintains a token cache.
app = msal.ConfidentialClientApplication(
    config["client_id"], authority=config["authority"],
    client_credential={"thumbprint": config["thumbprint"], "private_key": open(config['private_key_file']).read()},
    # token_cache=...  # Default cache is in memory only.
                       # You can learn how to use SerializableTokenCache from
                       # https://msal-python.rtfd.io/en/latest/#msal.SerializableTokenCache
    )
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
    .WithCertificate(certificate)
    .WithAuthority(new Uri(config.Authority))
    .Build();
 
高级方案:通过客户端断言实例化机密客户端应用程序
IClientCredential credential = ClientCredentialFactory.createFromClientAssertion(assertion);
ConfidentialClientApplication cca =
        ConfidentialClientApplication
                .builder(CLIENT_ID, credential)
                .authority(AUTHORITY)
                .build();
const clientConfig = {
    auth: {
        clientId: process.env.CLIENT_ID,
        authority: process.env.AAD_ENDPOINT + process.env.TENANT_ID,
        clientAssertion:  process.env.CLIENT_ASSERTION
    }
};
const cca = new msal.ConfidentialClientApplication(clientConfig);
有关详细信息,请参阅初始化 ConfidentialClientApplication 对象。
在 MSAL Python 中,可以使用将要由此 ConfidentialClientApplication 的私钥签名的声明来提供客户端声明。
# Pass the parameters.json file as an argument to this Python script. E.g.: python your_py_file.py parameters.json
config = json.load(open(sys.argv[1]))
# Create a preferably long-lived app instance that maintains a token cache.
app = msal.ConfidentialClientApplication(
    config["client_id"], authority=config["authority"],
    client_credential={"thumbprint": config["thumbprint"], "private_key": open(config['private_key_file']).read()},
    client_claims = {"client_ip": "x.x.x.x"}
    # token_cache=...  # Default cache is in memory only.
                       # You can learn how to use SerializableTokenCache from
                       # https://msal-python.rtfd.io/en/latest/#msal.SerializableTokenCache
    )
如需详细信息,请参阅 MSAL Python 的 ConfidentialClientApplication 参考文档。
机密客户端应用程序还可以使用客户端断言(而不是客户端密码或证书)来证明其身份。
MSAL.NET 可以通过两种方法将签名的断言提供给机密客户端应用:
- .WithClientAssertion()
- .WithClientClaims()
使用 WithClientAssertion 时,请提供签名的 JWT。 
              客户端断言详细介绍了这一高级方案。
string signedClientAssertion = ComputeAssertion();
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
                                          .WithClientAssertion(signedClientAssertion)
                                          .Build();
使用 WithClientClaims 时,MSAL.NET 会生成一个已签名断言,其中包含 Microsoft Entra ID 预期的声明,以及你想要发送的其他客户端声明。
此代码展示了如何执行该操作:
string ipAddress = "192.168.1.2";
var claims = new Dictionary<string, string> { { "client_ip", ipAddress } };
X509Certificate2 certificate = ReadCertificate(config.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
                                          .WithAuthority(new Uri(config.Authority))
                                          .WithClientClaims(certificate, claims)
                                          .Build();
同样,如需详细信息,请参阅客户端断言。
 
后续步骤