Microsoft Graph API 非管理员权限?

Microsoft Graph API Permissions for non-admins?

我正在尝试为我的 Office365 租户中的所有用户创建一个下拉列表。我在 Azure AD 中创建了一个应用程序并为其授予了所有必要的权限。实际上,我给了它 Microsoft Graph 的所有权限,应用程序和委托。全部。

然后我写了我的脚本来查询所有 https://graph.microsoft.com/v1.0/users 的用户。

我让我的租户管理员进入并接受权限,然后在 UI 中输出用户列表。适合管理员

我不是管理员,但是当我进入该页面时出现以下错误:

This application requires application permissions to another application. Consent for application permissions can only be performed by an administrator. Sign out and sign in as an administrator or contact one of your organization's administrators.

我想知道这是否适用于权限更低的用户。据我了解,API 请求和应用程序在 Azure 中授予应用程序的权限下 运行。因此,即使用户为只读,请求也不是 运行 在用户下,它是 运行 在我设置的应用程序下。那么为什么我会收到有关权限的错误?

这是我正在使用的代码:

(function () {
  "use strict";
  // Some samples will use the tenant name here like "tenant.onmicrosoft.com"
  // I prefer to user the subscription Id
  var subscriptionId = "metenant.onmicrosoft.com";
  // Copy the client ID of your AAD app here once you have registered one, configured the required permissions, and
  // allowed implicit flow https://msdn.microsoft.com/en-us/office/office365/howto/get-started-with-office-365-unified-api
  var clientId = "cccb1f2f-xxx-x-xxxxx-x-x-x-x-x-";

  window.config = {
    // subscriptionId: subscriptionId,
    clientId: clientId,
    postLogoutRedirectUri: window.location.origin,
    endpoints: {
      graphApiUri: 'https://graph.microsoft.com'
    },
    cacheLocation: 'localStorage' // enable this for IE, as sessionStorage does not work for localhost.
  };

  var authContext = new AuthenticationContext(config);

  // Check For & Handle Redirect From AAD After Login
  var isCallback = authContext.isCallback(window.location.hash);
  authContext.handleWindowCallback();

  if (isCallback && !authContext.getLoginError()) {
    window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
  }

  // If not logged in force login
  var user = authContext.getCachedUser();
  // NOTE: you may want to render the page for anonymous users and render
  // a login button which runs the login function upon click.
  if (!user) authContext.login();

  // Acquire token for Files resource.
  authContext.acquireToken(config.endpoints.graphApiUri, function (error, token) {
    // Handle ADAL Errors.
    if (error || !token) {
      console.log('ADAL error occurred: ' + error);
      return;
    }
    // Execute GET request to Files API.
    var filesUri = config.endpoints.graphApiUri + "/v1.0/users";
    $.ajax({
      type: "GET",
      url: filesUri,
      headers: {
        'Authorization': 'Bearer ' + token,
      }
    }).done(function (response) {
      console.log('Successfully fetched from Graph.');
      console.log(response);

      var container = $(".container")

      container.empty();

      $.each(response.value, function(index, item) {
        container.append($('<li>').text(item.displayName + " " + item.mail + " " + item.mobilePhone))
      })
    }).fail(function (response) {
      var err = JSON.parse(response.responseText)
      console.log('Failed:', err.error.message);
    });
  });
})();

Microsoft Graph 有两种 permission/scope。一种是需要管理员的同意。另一个不是必需的。

您为此应用配置的权限是什么?要列出未经管理员同意的用户,我们可以使用范围User.ReadBasic.All,如下图所示:

您可以从 here 获得有关 permission/scope 的更多详细信息。

修改:

目前,adal.js 不提供管理员同意。如果你想使用这个功能,你可以修改代码添加如下参数:

AuthenticationContext.prototype.login = function (prompt) {
// Token is not present and user needs to login
var expectedState = this._guid();
this.config.state = expectedState;
this._idTokenNonce = this._guid();
this._logstatus('Expected state: ' + expectedState + ' startPage:' + window.location);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_REQUEST, window.location);
this._saveItem(this.CONSTANTS.STORAGE.LOGIN_ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.STATE_LOGIN, expectedState);
this._saveItem(this.CONSTANTS.STORAGE.NONCE_IDTOKEN, this._idTokenNonce);
this._saveItem(this.CONSTANTS.STORAGE.FAILED_RENEW, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR, '');
this._saveItem(this.CONSTANTS.STORAGE.ERROR_DESCRIPTION, '');


var urlNavigate = this._getNavigateUrl('id_token', null) + '&nonce=' + encodeURIComponent(this._idTokenNonce);

if (prompt && prompt === "admin_consent") {
    urlNavigate = urlNavigate + "&prompt=admin_consent"
}


this.frameCallInProgress = false;
this._loginInProgress = true;
if (this.config.displayCall) {
    // User defined way of handling the navigation
    this.config.displayCall(urlNavigate);
} else {
    this.promptUser(urlNavigate);
}
// callback from redirected page will receive fragment. It needs to call oauth2Callback
};

如果你使用的是Angular,我们还需要修改adal-angular.js:

this.$get = ['$rootScope', '$window', '$q', '$location', '$timeout', function ($rootScope, $window, $q, $location, $timeout) {
... 
return {
                // public methods will be here that are accessible from Controller
                config: _adal.config,
                login: function (prompt) {
                _adal.login(prompt);
        },
...
}

那么我们可以提供两个按钮供用户登录。一个按钮供用户自己登录。另一个是管理员同意组织。这是在 Angular:

的控制下重定向到管理员同意的登录页面的代码
$scope.login = function () {
     adalService.login("admin_consent");
};