【问题标题】:MS Graph API (mail) issue with POST and scopesPOST 和范围的 MS Graph API(邮件)问题
【发布时间】:2021-02-16 15:44:36
【问题描述】:

试图让它工作并且 GET / Patch 工作得很好,但是 POST 给了我 HTTP STATUS 400 和 403。必须是有作用域的东西。在 Azure AD 中,我设置了以下范围:

Mail.ReadWrite (Delegated)
Mail.ReadWrite (Application)
Mail.Send Delegated)
Mail.Send (Application)

因此,登录工作正常,获取/修补消息也是如此。只有 POST 似乎不起作用。 有关确切的错误消息,请参阅代码。

Angular10

App.module

export function MSALInstanceFactory(): IPublicClientApplication {
      return new PublicClientApplication({
        auth: {
          clientId: 'xxxx',
          authority: 'https://login.microsoftonline.com/common/',
          redirectUri: '/',
          postLogoutRedirectUri: '/#/login'
        },
        cache: {
          cacheLocation: BrowserCacheLocation.LocalStorage,
          storeAuthStateInCookie: isIE, // set to true for IE 11
        },
        system: {
          loggerOptions: {
            loggerCallback,
            logLevel: LogLevel.Info,
            piiLoggingEnabled: false
          }
        }
      });
    }

    export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
      const protectedResourceMap = new Map<string, Array<string>>();
      protectedResourceMap.set('https://graph.microsoft.com/v1.0/me', ['user.read', 'mail.readWrite', 'email']);
      // also tried these scopes .. 
      // protectedResourceMap.set('https://graph.microsoft.com/v1.0', ['user.read', 'mail.readWrite', 'email']);
      // protectedResourceMap.set('https://graph.microsoft.com/v1.0/query', ['user.read', 'mail.readWrite', 'email']);
      // protectedResourceMap.set('https://graph.microsoft.com/v1.0/search/query', ['user.read', 'mail.readWrite', 'email']);

      return {
        interactionType: InteractionType.Redirect,
        protectedResourceMap
      };
    }

    export function MSALGuardConfigFactory(): MsalGuardConfiguration {
      return { interactionType: InteractionType.Redirect };
    }

@NgModule({
    imports: [
      BrowserModule,
      // etc..
    ],
    declarations: [AppComponent],
    providers: [
      NgEventBus,
      ChhServices,
      SynclogService,
      AppService,
      AuthService,
      GapiServices,
      {
        provide: ErrorHandler,
        useClass: ErrorService,
      },
      {
        provide: HTTP_INTERCEPTORS,
        useClass: MsalInterceptor,
        multi: true
      },
      {
        provide: MSAL_INSTANCE,
        useFactory: MSALInstanceFactory
      },
      {
        provide: MSAL_GUARD_CONFIG,
        useFactory: MSALGuardConfigFactory
      },
      {
        provide: MSAL_INTERCEPTOR_CONFIG,
        useFactory: MSALInterceptorConfigFactory
      },
      MsalService,
      MsalGuard,
      MsalBroadcastService
    ],
    bootstrap: [AppComponent],
  })
  export class AppModule { }

身份验证服务

signIn() {
    console.log('AuthService::signIn');
    this.msalService.loginPopup().subscribe((result) => {
        this.accessToken = result['accessToken'];
        console.log('authority', result, this.accessToken);
    });
}

testGraphApi() {

    // 200 OK
    const apiGet = this.httpClient.get(`https://graph.microsoft.com/v1.0/me/messages/`).subscribe((data) => {
        console.log('get', '/me/messages', data);
    });

    const categories: any[] = ['custom'];
    const body = {
        subject: '2320, with tags',
        flag: { flagStatus: 'flagged' }, // notFlagged
        categories,
        body: {
            contentType: 'html',
            content: 'lalala'
        },
        inferenceClassification: 'other'
    };

    const id = 'AQMkADAwATM3ZmYAZS0zOTkANy02MTAwAC0wMAItMDAKAEYAAAM_TfJTK-tISYhjZdaCkkbgBwCPpkVcscQ9QJF-EDzB8h_oAAACAQwAAACPpkVcscQ9QJF-EDzB8h_oAAACHbIAAAA=';

    // 200 OK
    const apiPatch = this.httpClient.patch(`https://graph.microsoft.com/v1.0/me/messages/${id}`, body).subscribe((data) => {
        console.log('patch', '/me/messages', data);
    });

    const bodySendMail = {
        'message': {
            'subject': 'Meet for lunch?',
            'body': {
                'contentType': 'Text',
                'content': 'The new cafeteria is open.'
            },
            // etc..
        }
    }

    const headers = new HttpHeaders({ 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.accessToken}` });

    // 403 Forbidden
    // "code": "ErrorAccessDenied",
    // "message": "Access is denied. Check credentials and try again.",
    const apiSendMail = this.httpClient.post(`https://graph.microsoft.com/v1.0/me/sendMail`, bodySendMail, { headers }).subscribe((data) => {
        console.log('post', '/me/sendMail', data);
    });

    const bodySearch = {
        'requests': [
            {
                'entityTypes': [
                    'message'
                ],
                'query': {
                    'queryString': 'ref:6019d6bf1ce3425fb833559e'
                },
                'from': 0,
                'size': 5
            }
        ]
    }

    // 400 Bad Request
    // "code": "AuthenticationError",
    // "message": "Error authenticating with resource",
    const apiSearch = this.httpClient.post(`https://graph.microsoft.com/v1.0/search/query`, bodySearch, { headers }).subscribe((data) => {
        console.log('post', '/search/query', data);
    });
}

【问题讨论】:

  • 我试过'/me/sendMail'和'/search/query'的api,都可以得到正确的响应。对于您的403错误,我认为您可以尝试使用'/users/{user id}'替换'/me'来排除错误流的错误。顺便说一句,您用来发送邮件的访问令牌更有可能没有正确的范围,我真的没有在您的代码中找到范围“Mail.Send”。对于 400 错误,我已将您的请求正文 json 对象复制到我的请求中并且它确实有效,所以我认为它也可能是由错误访问令牌引起的。我使用了 ropc 流程,它使用用户 ID 和密码来生成令牌。
  • 以上有帮助吗?
  • @tiny-wa 1. ROPC 流程似乎不适合我的应用程序目的,服务于更大的匿名受众,但是,出于测试目的,它值得一试。 2. [mail.send] 已添加到范围中,现在可以正常工作了,所以谢谢 :-) 忽略了那个。 3. 似乎路径 /search/query 在组合中与我的令牌不被接受,是的.. 感觉就像我快到了,因为 post 和 patch 正在使用 /me 路径。仍在调查。
  • @SanJayFalcon 感谢您的回复,在出现 400 错误时,我认为您应该确保您使用的是具有 Delegated 权限的工作或学校帐户,它在 docs 中定义,只有这个可以支持如果您使用的是个人帐户,可能会导致 400 错误。
  • 是的,工作/学校帐户仅支持委派权限。如果您使用的是应用场景,则不支持。据说我看到你正在调用 /me 端点,所以它不是应用场景。因此,只需确定您使用的是哪个帐户(个人/工作和学校)...

标签: post azure-active-directory microsoft-graph-api angular10 scopes


【解决方案1】:
// 403 Forbidden
// "code": "ErrorAccessDenied",
// "message": "Access is denied. Check credentials and try again."

Send mail API 需要Mail.Send 权限。当请求基于当前登录用户的/me端点时,它应该具有委派权限

所以你需要在门户中添加Mail.Send的委派权限,并添加到你的代码中。

// 400 Bad Request
// "code": "AuthenticationError",
// "message": "Error authenticating with resource"

searchEntity: query API 需要Mail.ReadWrite 委派权限。此 api 仅支持“工作或学校帐户”。工作帐户通常使用组织的自定义域名或公司名称,例如“jon@contoso.com”或“xxx@yourTenantName.onmicrosoft.com”。

您可以测试以请求Graph Explorer中的api。

【讨论】:

    猜你喜欢
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 2016-11-07
    相关资源
    最近更新 更多