• 集成 Windows 身份验证仅可用于“联合 +”用户,即在 Active Directory 中创建并受 Azure AD 支持的用户。 直接在 Azure AD 中创建的但不是由 Active Directory 支持的用户(称为“托管用户”)不能使用此身份验证流。 此项限制不影响用户名和密码流。

  • IWA 不会绕过 多重身份验证 (MFA) 。 如果已配置 MFA,则在需要 MFA 质询的情况下,IWA 可能失败,因为 MFA 需要用户交互。

    IWA 是非交互式的,但 MFA 需要用户交互。 标识提供者何时请求执行 MFA 并不由你控制,而是由租户管理员控制。 根据观察,在以下情况下需要 MFA:当你从不同国家/地区登录时;未通过 VPN 连接到公司网络时;有时甚至通过 VPN 连接也需要 MFA。 规则并不确定。 Azure AD 使用 AI 来持续判断是否需要执行 MFA。 如果 IWA 失败,则回退到用户提示,例如交互式身份验证或设备代码流。

  • PublicClientApplicationBuilder 中传入的颁发机构需要:

  • 租户化(采用 https://login.microsoftonline.com/{tenant}/ 格式,其中, tenant 是表示租户 ID 或者与该租户关联的域的 GUID)。
  • 对于任何工作和学校帐户: https://login.microsoftonline.com/organizations/
  • 不支持 Microsoft 个人帐户。 不能使用 /common 或 /consumers 租户。
  • 因为集成 Windows 身份验证是一个无提示流:

  • 应用程序的用户必须已事先许可使用该应用程序。
  • 或者,租户管理员必须已事先许可租户中的所有用户使用该应用程序。
  • 换句话说:
    • 开发人员已在 Azure 门户中自行选择“授予”按钮。
    • 或者,租户管理员已在应用程序注册的“API 权限”选项卡中选择“授予/撤销 {租户域} 的管理员许可”按钮。 有关详细信息,请参阅 添加访问 Web API 的权限
    • 或者,你已提供某种方式让用户许可应用程序。 有关详细信息,请参阅 请求单个用户的许可
    • 或者,你已提供某种方式让租户管理员许可应用程序。 有关详细信息,请参阅 管理员许可
    • AcquireTokenByIntegratedWindowsAuth(IEnumerable<string> scopes)
      

      通常只需要一个参数 (scopes)。 根据 Windows 管理员设置策略的方式,有可能不允许 Windows 计算机上的应用程序查找已登录的用户。 在这种情况下,请使用另一个方法 .WithUsername(),并以 UPN 格式(例如 joe@contoso.com)传入已登录用户的用户名。

      下面的示例展示了最新的情况,并说明了可获取的异常类型以及缓解措施。

      static async Task GetATokenForGraph()
       string authority = "https://login.microsoftonline.com/contoso.com";
       string[] scopes = new string[] { "user.read" };
       IPublicClientApplication app = PublicClientApplicationBuilder
            .Create(clientId)
            .WithAuthority(authority)
            .Build();
       var accounts = await app.GetAccountsAsync();
       AuthenticationResult result = null;
       if (accounts.Any())
        result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
            .ExecuteAsync();
         result = await app.AcquireTokenByIntegratedWindowsAuth(scopes)
            .ExecuteAsync(CancellationToken.None);
        catch (MsalUiRequiredException ex)
         // MsalUiRequiredException: AADSTS65001: The user or administrator has not consented to use the application
         // with ID '{appId}' named '{appName}'.Send an interactive authorization request for this user and resource.
         // you need to get user consent first. This can be done, if you are not using .NET Core (which does not have any Web UI)
         // by doing (once only) an AcquireToken interactive.
         // If you are using .NET core or don't want to do an AcquireTokenInteractive, you might want to suggest the user to navigate
         // to a URL to consent: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={clientId}&response_type=code&scope=user.read
         // AADSTS50079: The user is required to use multi-factor authentication.
         // There is no mitigation - if MFA is configured for your tenant and AAD decides to enforce it,
         // you need to fallback to an interactive flows such as AcquireTokenInteractive or AcquireTokenByDeviceCode
         catch (MsalServiceException ex)
          // Kind of errors you could have (in ex.Message)
          // MsalServiceException: AADSTS90010: The grant type is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint.
          // you used common.
          // Mitigation: as explained in the message from Azure AD, the authority needs to be tenanted or otherwise organizations
          // MsalServiceException: AADSTS70002: The request body must contain the following parameter: 'client_secret or client_assertion'.
          // Explanation: this can happen if your application was not registered as a public client application in Azure AD
          // Mitigation: in the Azure portal, edit the manifest for your application and set the `allowPublicClient` to `true`
         catch (MsalClientException ex)
            // Error Code: unknown_user Message: Could not identify logged in user
            // Explanation: the library was unable to query the current Windows logged-in user or this user is not AD or AAD
            // joined (work-place joined users are not supported).
            // Mitigation 1: on UWP, check that the application has the following capabilities: Enterprise Authentication,
            // Private Networks (Client and Server), User Account Information
            // Mitigation 2: Implement your own logic to fetch the username (e.g. john@contoso.com) and use the
            // AcquireTokenByIntegratedWindowsAuth form that takes in the username
            // Error Code: integrated_windows_auth_not_supported_managed_user
            // Explanation: This method relies on a protocol exposed by Active Directory (AD). If a user was created in Azure
            // Active Directory without AD backing ("managed" user), this method will fail. Users created in AD and backed by
            // AAD ("federated" users) can benefit from this non-interactive method of authentication.
            // Mitigation: Use interactive authentication
       Console.WriteLine(result.Account.Username);
      

      有关 AcquireTokenByIntegratedWindowsAuthentication 上可能的修饰符列表,请参阅 AcquireTokenByIntegratedWindowsAuthParameterBuilder

      此代码摘录自 MSAL Java 代码示例

         PublicClientApplication pca = PublicClientApplication.builder(clientId)
                      .authority(authority)
                      .build();
              Set<IAccount> accountsInCache = pca.getAccounts().join();
              IAccount account = getAccountByUsername(accountsInCache, username);
              //Attempt to acquire token when user's account is not in the application's token cache
              IAuthenticationResult result = acquireTokenIntegratedWindowsAuth(pca, scope, account, username);
              System.out.println("Account username: " + result.account().username());
              System.out.println("Access token:     " + result.accessToken());
              System.out.println("Id token:         " + result.idToken());
              System.out.println();
              //Get list of accounts from the application's token cache, and search them for the configured username
              //getAccounts() will be empty on this first call, as accounts are added to the cache when acquiring a token
              accountsInCache = pca.getAccounts().join();
              account = getAccountByUsername(accountsInCache, username);
              //Attempt to acquire token again, now that the user's account and a token are in the application's token cache
              result = acquireTokenIntegratedWindowsAuth(pca, scope, account, username);
              System.out.println("Account username: " + result.account().username());
              System.out.println("Access token:     " + result.accessToken());
              System.out.println("Id token:         " + result.idToken());
          private static IAuthenticationResult acquireTokenIntegratedWindowsAuth( PublicClientApplication pca,
                                                                                  Set<String> scope,
                                                                                  IAccount account,
                                                                                  String username) throws Exception {
              IAuthenticationResult result;
              try {
                  SilentParameters silentParameters =
                          SilentParameters
                                  .builder(scope)
                                  .account(account)
                                  .build();
                  // Try to acquire token silently. This will fail on the first acquireTokenIntegratedWindowsAuth() call
                  // because the token cache does not have any data for the user you are trying to acquire a token for
                  result = pca.acquireTokenSilently(silentParameters).join();
                  System.out.println("==acquireTokenSilently call succeeded");
              } catch (Exception ex) {
                  if (ex.getCause() instanceof MsalException) {
                      System.out.println("==acquireTokenSilently call failed: " + ex.getCause());
                      IntegratedWindowsAuthenticationParameters parameters =
                              IntegratedWindowsAuthenticationParameters
                                      .builder(scope, username)
                                      .build();
                      // Try to acquire a token using Integrated Windows Authentication (IWA). You will need to generate a Kerberos ticket.
                      // If successful, you should see the token and account information printed out to console
                      result = pca.acquireToken(parameters).join();
                      System.out.println("==Integrated Windows Authentication flow succeeded");
                  } else {
                      // Handle other exceptions accordingly
                      throw ex;
              return result;
      
  •