为什么我的Azure Active Directory身份验证令牌不包含MS Graph的权限?

为什么我的Azure Active Directory身份验证令牌不包含MS Graph的权限?,azure,azure-active-directory,microsoft-graph-api,Azure,Azure Active Directory,Microsoft Graph Api,在我开始编写应用程序代码之前,我在邮递员公司工作,这样我就可以了解我实际上应该做什么——这是一种教育;在实际的应用程序开发中,我将使用MSAL进行身份验证 与此同时,我甚至无法获得有效的代币 Azure上的我的应用程序在Azure门户的API权限刀片中设置了Calendar.Read和Calendar.ReadWrite权限 我已经为应用程序创建了一个客户端密码,因此使用客户端凭据流,我提供了每个的/.default作用域 当我尝试在以下位置查询MS graph时:https://graph.m

在我开始编写应用程序代码之前,我在邮递员公司工作,这样我就可以了解我实际上应该做什么——这是一种教育;在实际的应用程序开发中,我将使用MSAL进行身份验证

与此同时,我甚至无法获得有效的代币

Azure上的我的应用程序在Azure门户的API权限刀片中设置了Calendar.Read和Calendar.ReadWrite权限

我已经为应用程序创建了一个客户端密码,因此使用客户端凭据流,我提供了每个的/.default作用域

当我尝试在以下位置查询MS graph时:https://graph.microsoft.com/v1.0/users//events 我得到的错误是:

令牌不包含权限,或者权限无法理解

果然,令牌既不包含scp也不包含角色声明

我还引用了获取令牌以及在Postman中配置请求

我不明白我错在哪里。据我所知,我做的每件事都是我应该做的,但我只是一事无成

我哪里做错了?我错过什么了吗?我做错什么了吗

这是我从Postman那里得到的jquery代码:

var settings = {
  "url": "https://login.microsoftonline.com/redacted/oauth2/token",
  "method": "POST",
  "timeout": 0,
  "headers": {
    "Content-Type": "application/x-www-form-urlencoded"
  },
  "data": {
    "grant_type": "client_credentials",
    "client_id": "redacted",
    "client_secret": "redacted",
    "resource": "https://graph.microsoft.com",
    "scope": "./default"
  }
};

$.ajax(settings).done(function (response) {
  console.log(response);
});
非常感谢你的帮助


提前感谢

如果您正在使用隐式流,请看一看。否则,将出现最大长度问题,令牌的内容将被截断


如果您使用的是隐式流,请看一看,否则会出现最大长度问题,令牌的内容将被截断


你用哪种语言?在我看来,不能使用jquery发送ajax请求来获取访问令牌,这应该是CORS错误

同时,应该在守护程序应用程序中使用客户端凭据流,但您提供的代码可能是单页应用程序。这里有一个文档包含许多不同类型应用程序的示例,您可以选择其中一个来生成您的访问令牌

这是我关于获取调用密钥库的访问令牌的建议,您可以参考。如果我在某个地方误解了,请指出。您还可以提供有关进一步问题的更多详细信息

=========================================================

前端代码,从后端获取访问令牌并调用graph api:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    </head>
    <body>
        <div>
            <div id="subject"></div>
            <div>create time: <span id="cDateTime"></span></div>
            
        </div>
        <script src="../js/jquery-3.5.1.min.js"></script>
        <script type="text/javascript">
            $(function() {
                initPage();
            });
            
            function initPage(){
                $.ajax({
                    url: "https://localhost:44343/",
                    type: 'get',
                    contentType: "application/json;charset=utf-8",
                    success: function(data) {
                        callApi(data);
                    },
                    error: function(data) {
                        console.info(data);
                    }
                })
            }
            
            function callApi(accesstoken){
                $.ajax({
                    url: "https://graph.microsoft.com/v1.0/users/{user_id_here}/calendar/events",
                    type: 'get',
                    headers: {
                        Authorization: "Bearer " + accesstoken
                    },
                    dataType: 'json',
                    success: function(data) {
                        var createdDateTime = data.value[0].createdDateTime;
                        var subject = data.value[0].subject;
                        $("#subject").html(subject);
                        $("#cDateTime").html(createdDateTime);
                    },
                    error: function(data) {
                        console.info(data);
                    }
                })
            }
        </script>
    </body>
</html>
后端codehome控制器,使用客户端凭据流生成访问令牌,并将其发送到前端。如果您选择使用前端后端分离,请不要忘记处理核心错误

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
using System;
using System.Threading.Tasks;


namespace crendentailflow_web_mvc.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public async Task<string> Index()
        {
            //I saved the client secret in azure key vault, and you can aslo use it directly
            const string secretName = "clientsecret";
            var kvUri = "https://vaultname.vault.azure.net/";
            var a = new DefaultAzureCredential();
            var client = new SecretClient(new Uri(kvUri), a);
            var secret = await client.GetSecretAsync(secretName);
            string secretVaule = secret.Value.Value;

            IConfidentialClientApplication app;
            app = ConfidentialClientApplicationBuilder.Create("azure_ad_app_client_id")
                    .WithClientSecret(secretVaule)
                    .WithAuthority(new Uri("https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com"))
                    .Build();

            AuthenticationResult result = null;
            // don't forget to add api permission in azure portal
            string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
            result = await app.AcquireTokenForClient(scopes)
                    .ExecuteAsync();
            string accesstoken = result.AccessToken;
            return accesstoken;
        }
    }
}
依赖项:

<PackageReference Include="Azure.Identity" Version="1.4.0" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.1.0" />

你用哪种语言?在我看来,不能使用jquery发送ajax请求来获取访问令牌,这应该是CORS错误

同时,应该在守护程序应用程序中使用客户端凭据流,但您提供的代码可能是单页应用程序。这里有一个文档包含许多不同类型应用程序的示例,您可以选择其中一个来生成您的访问令牌

这是我关于获取调用密钥库的访问令牌的建议,您可以参考。如果我在某个地方误解了,请指出。您还可以提供有关进一步问题的更多详细信息

=========================================================

前端代码,从后端获取访问令牌并调用graph api:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    </head>
    <body>
        <div>
            <div id="subject"></div>
            <div>create time: <span id="cDateTime"></span></div>
            
        </div>
        <script src="../js/jquery-3.5.1.min.js"></script>
        <script type="text/javascript">
            $(function() {
                initPage();
            });
            
            function initPage(){
                $.ajax({
                    url: "https://localhost:44343/",
                    type: 'get',
                    contentType: "application/json;charset=utf-8",
                    success: function(data) {
                        callApi(data);
                    },
                    error: function(data) {
                        console.info(data);
                    }
                })
            }
            
            function callApi(accesstoken){
                $.ajax({
                    url: "https://graph.microsoft.com/v1.0/users/{user_id_here}/calendar/events",
                    type: 'get',
                    headers: {
                        Authorization: "Bearer " + accesstoken
                    },
                    dataType: 'json',
                    success: function(data) {
                        var createdDateTime = data.value[0].createdDateTime;
                        var subject = data.value[0].subject;
                        $("#subject").html(subject);
                        $("#cDateTime").html(createdDateTime);
                    },
                    error: function(data) {
                        console.info(data);
                    }
                })
            }
        </script>
    </body>
</html>
后端codehome控制器,使用客户端凭据流生成访问令牌,并将其发送到前端。如果您选择使用前端后端分离,请不要忘记处理核心错误

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
using System;
using System.Threading.Tasks;


namespace crendentailflow_web_mvc.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;

        public HomeController(ILogger<HomeController> logger)
        {
            _logger = logger;
        }

        public async Task<string> Index()
        {
            //I saved the client secret in azure key vault, and you can aslo use it directly
            const string secretName = "clientsecret";
            var kvUri = "https://vaultname.vault.azure.net/";
            var a = new DefaultAzureCredential();
            var client = new SecretClient(new Uri(kvUri), a);
            var secret = await client.GetSecretAsync(secretName);
            string secretVaule = secret.Value.Value;

            IConfidentialClientApplication app;
            app = ConfidentialClientApplicationBuilder.Create("azure_ad_app_client_id")
                    .WithClientSecret(secretVaule)
                    .WithAuthority(new Uri("https://login.microsoftonline.com/your_tenant_name.onmicrosoft.com"))
                    .Build();

            AuthenticationResult result = null;
            // don't forget to add api permission in azure portal
            string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
            result = await app.AcquireTokenForClient(scopes)
                    .ExecuteAsync();
            string accesstoken = result.AccessToken;
            return accesstoken;
        }
    }
}
依赖项:

<PackageReference Include="Azure.Identity" Version="1.4.0" />
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.1.0" />

好的,这就是问题所在,您尚未授予Calendars.Read或Calendars.ReadWrite应用程序权限

因为您正在使用客户端凭据流来获取令牌,并调用/users/{user id}端点来列出其他用户的事件。因此,您必须授予应用程序权限,并授予该权限的管理员同意。那你的问题就解决了


好的,这就是问题所在,您尚未授予Calendars.Read或Calendars.ReadWrite应用程序权限

因为您正在使用客户端凭据流来获取令牌,并调用/users/{user id}端点来列出其他用户的事件。因此,您必须授予应用程序权限,并授予该权限的管理员同意。那你的问题就解决了


因此,我的预期用途是在web界面上显示实时共享日历。我们想在办公室里设置显示共享日历的电视屏幕。SPA很好,我看了很多样品,我一直在做样品,但即使是这里的样品也无法连接到我的日历,所以我真的在抓救命稻草。。。根据你的话,你可以在我下载的示例中看到这一点,似乎最好使用客户端凭据流来生成访问令牌,并调用graph api来获取日历数据,这样你就不需要登录你的程序了azure提供的其他流是必需的
red登录,然后可以获得用于调用api的访问令牌。让我试着为您提供一个后端MVC程序示例。因此,我在这里的预期用途是在web界面上显示实时共享日历。我们想在办公室里设置显示共享日历的电视屏幕。SPA很好,我看了很多样品,我一直在做样品,但即使是这里的样品也无法连接到我的日历,所以我真的在抓救命稻草。。。你可以从我根据你的话下载的样本中看到这一点,似乎最好使用客户端凭据流来生成访问令牌,并调用graph api来获取日历数据,这样您就不需要登录您的程序。azure提供的其他流需要登录,然后才能获取用于调用api的访问令牌。让我尝试为您提供一个后端MVC程序示例。您在添加应用程序权限时是否授予管理员同意?@CarlZhao委托的权限具有管理员同意,但我没有适当的权限授予应用程序权限的管理员同意我甚至不确定是否首先需要这些权限客户端\u凭据使用应用程序权限独占。委派的权限只能与经过身份验证的用户一起使用。如果我的回答对您有帮助,您可以将其更改为结束线程。谢谢添加应用程序权限时,您是否授予管理员同意?@CarlZhao委托的权限具有管理员同意,但我没有授予应用程序权限管理员同意的适当权限我甚至不确定是否首先需要这些权限客户端\u凭据仅使用应用程序权限。委派的权限只能与经过身份验证的用户一起使用。如果我的回答对您有帮助,您可以将其更改为结束线程。谢谢