【问题标题】:Microsoft graph - Access token validation failure. Invalid audience - ErrorMicrosoft graph - 访问令牌验证失败。无效的观众 - 错误
【发布时间】:2021-01-07 20:59:11
【问题描述】:

我正在尝试使用 Angular 应用程序中的 Graph API 发送邮件。

在 Azure 活动目录中,我已授予 Mail.Send 和其他邮件相关内容的 API 权限。

下面是代码

const resource = {
    grant_type : 'client_credentials',
    clientID: '****************************',
    redirectUri: 'http://localhost:4200/',
    validateAuthority : true,
    popUp: true,
    scopes: ['mail.send'],
    resource : 'https://graph.microsoft.com'
  };

  let murl : any
  murl = 'https://graph.microsoft.com/v1.0/users/' + 'testuser@abcd.onmicrosoft.com' + '/sendMail';

  this.token = await this.msalService.acquireTokenSilent(resource)
      .catch((reason) => {
        // console.log(reason);
      });

      let header = new HttpHeaders({
        'Content-Type': 'application/json',
          'Authorization': 'Bearer ' + this.token.accessToken});
      let options = { headers: header };

      let resp =  this.http.post(murl, this.sendMailDet, options)
       resp.subscribe(
          (data)=>{
            console.log( data);
        }
        );

但是当我发送邮件时出现以下错误。

error: {code: "InvalidAuthenticationToken", message: "Access token validation failure. Invalid audience.",…}
code: "InvalidAuthenticationToken"
innerError: {date: "2021-01-06T04:52:20", request-id: "*********",…}
message: "Access token validation failure. Invalid audience."

我在资源中使用范围:['mail.send'] 仍然收到此错误。我也只使用 this.msalService.acquireTokenSilent(resource) 中的 accessToken。

jwt.ms 中的令牌将 aud 显示为“aud”:“https://graph.microsoft.com”, 和“scp”:“Directory.Read.All email Mail.Read Mail.Read.Shared Mail.ReadBasic Mail.ReadWrite Mail.ReadWrite.Shared Mail.Send Mail.Send.Shared MailboxSettings.Read MailboxSettings.ReadWrite User.Export.All User.Invite.All User.ManageIdentities.All User.Read User.Read.All User.ReadBasic.All User.ReadWrite User.ReadWrite.All profile openid",

谁能帮我检查一下这个问题。

【问题讨论】:

  • acquireTokenSilent 方法被调用时,库首先检查浏览器存储中的缓存以查看是否存在有效令牌并返回它。所以实际上你在这里并没有获得 Microsoft Graph 的应用程序令牌。
  • 我注意到您使用client_credentials 作为grant_type,这意味着您想使用应用程序令牌而不是用户令牌。对吗?
  • 嗨@AllenWu,最初当用户登录时,将获得一个用于应用程序的令牌。但是要发送邮件,我会使用包含范围的不同令牌。我得到了一个不同的令牌。我在 jwt.ms 中验证并找到了范围(我在最后一部分提到的问题)。所以我认为令牌是正确的。还是我错过了什么?
  • 嗯,实际上我从不同的来源尝试过这个,这个 client_credentials 在那个样本中。我的目标是从用户帐户发送邮件。那么我是否必须更改grant_type 中的任何内容:'client_credentials'?
  • 没有。令牌 NOT 正确。这就是为什么我问你“你想使用应用程序令牌而不是用户令牌?”。对于client_credentials 流获取的正确令牌,应该有roles 声明而不是scp 声明。而roles 声明是应用程序许可。 scp 声明是委托权限。当您在 AAD 应用程序中添加它时,您应该能够找到这两种类型的权限。

标签: angular authentication microsoft-graph-api access-token


【解决方案1】:

我必须从 angular 发送令牌,因为首先会显示接受或取消弹出窗口。所以不得不从角度处理。 但这给了我问题中提到的错误。所以我为此创建了一个 API,并从 Angular 发送令牌和其他详细信息。

这是 Angular 部分

data : 带有 From、To、CC、bcc、emailbody 等的对象。使用这些值,我们在 API 中创建 json 电子邮件格式

async sendmail(data): Promise<Boolean>  
  {

    let result : any ; 
    const resource = {
      clientID: environment.config.identityConfig.clientId , 
      redirectUri: environment.config.identityConfig.redirectUri , // 'http://localhost:4200/'
      validateAuthority : true,
      popUp: true,
      scopes: ['mail.send'],
      resource : 'https://graph.microsoft.com'
    };
    this.token = await this.msalService.acquireTokenSilent(resource)
    .catch((reason) => {
      console.log(reason);
    });

    this.atoken = this.token.accessToken;
    data.EMailAccessToken = this.token.accessToken;
    this.mailHttpService.post('/sendmailgapi', data, null, null, ApiUrl.FileService). // This is custom 
   subscribe((data) => {
     result = data; 
   });

   return result;
  }

然后在 API 中,

this.applicationContext.GetGraphClient() :这是另一种使用客户端 ID、租户 ID、ClientSecret 和使用 ConfidentialClientApplicationBuilder 的方法,我们创建了一个 Graph 客户端。

sendMailDto : 传递对象

GraphServiceClient graphClient = this.applicationContext.GetGraphClient();
var fromEmail = sendMailDto.EMailFrom ; // 
var accessToken = sendMailDto.EMailAccessToken;
var message = createMessage(sendMailDto);
var restClient = new RestClient("https://graph.microsoft.com/v1.0/users/" + fromEmail + "/sendMail");
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer " + accessToken 
request.AddParameter("", message, ParameterType.RequestBody);
IRestResponse response = restClient.Execute(request);
               

我不确定这是否是正确的方法,但我必须采取一种变通方法来解决问题。

【讨论】:

    猜你喜欢
    • 2021-06-13
    • 2021-03-21
    • 2022-08-16
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 2017-11-26
    • 1970-01-01
    • 2017-05-19
    相关资源
    最近更新 更多