尝试使用 Microsfot GraphAPI 发送电子邮件时出现 TenantGuidNotFound

问题描述 投票:0回答:1

我正在尝试在 Laravel 应用程序中使用 Microsft GraphAPI 发送电子邮件。我能够通过这个函数成功获取访问令牌。

public function getAccessToken() {
        $tennantId = 'someID';
        $scope = 'https://graph.microsoft.com/.default';
        $appId = 'someAppID';
        $secretId = 'secretID';
        $secret = 'someSecretString';
        $url = "https://login.microsoftonline.com/{$tennantId}/oauth2/v2.0/token?scope={$scope}&client_id={$secretId}";

        $config = [
            'grant_type' => 'client_credentials',
            'client_id' => $appId,
            'client_secret' => $secret,
            'scope' => $scope,
        ];

        $response = Http::asForm()->post($url, $config);

        $data = $response->json();

        $token = Arr::get($data, 'access_token');
        
        return $token;
    }

当我使用 jwt.io 解码收到的访问令牌时,我得到了这个。

{
  "aud": "https://graph.microsoft.com",
  "iss": "https://sts.windows.net/**********************/",
  "iat": 1727514977,
  "nbf": 1727514977,
  "exp": 1727518877,
  "aio": "k2BgYGiT2uLUtyghU2/p5IaN16YKAAA=",
  "app_displayname": "Mailer Oauth2",
  "appid": "***************************",
  "appidacr": "1",
  "idp": "https://sts.windows.net/***************************/",
  "idtyp": "app",
  "oid": "c4addf3b-ab49-4270-bbf8-a2a4d832c560",
  "rh": "0.ARMBkUlDtYDgK02i7VB0sFJDagMAAAAAAAAAwAAAAAAAAAAUAQA.",
  "roles": [
    "Mail.ReadWrite",
    "Mail.ReadBasic.All",
    "Mail.Read",
    "Mail.Send",
    "Mail.ReadBasic"
  ],
  "sub": "c4addf3b-ab49-4270-bbf8-a2a4d832c560",
  "tenant_region_scope": "EU",
  "tid": "*************************************",
  "uti": "bC3CrECPGEOLobarnNDrAA",
  "ver": "1.0",
  "wids": [
    "0997a1d0-0d1d-4acb-b408-d5ca73121e90"
  ],
  "xms_idrel": "10 7",
  "xms_tcdt": 1727427193
}

在角色属性下,我可以看到 Mail.Send 存在。

当我尝试使用此代码发送电子邮件时

$emailData = [
            'message' => [
                'subject' => [$this->subject],
                'body' => [
                    'contentType' => 'HTML', 
                    'content' => $newTemplate, 
                ]
            ],
                'bccRecipients' => [
                    [
                        'emailAddress' => [
                            'address' => $this->mails->toArray()
                        ]
                    ]
                ],
                'attachments' => [
                    [
                        '@odata.type' => '#microsoft.graph.fileAttachment',
                        'name' => basename($srcImage),
                        'contentBytes' => base64_encode(file_get_contents($srcImage)), 
                        'contentId' => 'image', 
                    ],
                ],
        ];

        
        $response = Http::withToken($this->token)
            ->post("https://graph.microsoft.com/v1.0/users/{$this->email->email}/sendMail", [
                'message' => $emailData['message'],
                'saveToSentItems' => 'true', 
            ]);

但我收到此错误

{"error":{"code":"OrganizationFromTenantGuidNotFound","message":"The tenant for tenant guid '***************************' does not exist.","innerError":{"oAuthEventOperationId":"d630a3bf-f7b2-4373-872f-6618f21d7429","oAuthEventcV":"bXHKl4PYUfE8FIF62ShkHA.1.1","errorUrl":"https://aka.ms/autherrors#error-InvalidTenant","requestId":"e131128d-d6f1-43da-85ac-88799cac7cac","date":"2024-09-28T09:30:39"}
}}

这是我的 Azure 应用程序的屏幕截图(“应用程序权限”选项卡) Azure screenshot

我在互联网上搜索过,发现在选择访问令牌时应该使用关键字“common”,而不是使用实际的tennantID...我已经尝试过,但收到错误消息,指出tennantID无效并且我无法选择访问令牌。

https://login.microsoftonline.com/common/oauth2/v2.0/token?scope={$scope}&client_id={$secretId}

我在 Azure 应用程序中选择了多租户,如屏幕截图所示 Azure screenshot

老实说,我对 Microsoft Azure 的经验不是很丰富...我认为问题可能出在某些 Azure 定义中,但我不知道出在哪里。如有任何帮助,我们将不胜感激。

laravel azure microsoft-entra-id
1个回答
0
投票

Microsoft 也提出了类似的问题。最佳答案是

嗨@U安东

发生错误 401 未经授权的“OrganizationFromTenantGuidNotFound” 当您的 Azure AD 没有 Office 365 帐户可以使用时。

如果您想访问开发 O365 租户的消息, 在创建时获得的 O365 AAD 租户中注册应用程序 开发租户。

请按照以下步骤操作:

You need Microsoft 365 account with subscription
In your azure portal login with your Office 365 account
Create app in Azure active directory under App registration and give permissions according to the documentation
Then use your messages endpoint for users

您使用此 API 获取用户数据 users/{users-id} 因为它 Azure AD 端点

当我解码你的令牌时,我发现你正在使用应用程序 我/消息端点的令牌。

您需要具有权限“Mail.ReadBasic、Mail.Read、 Mail.ReadWrite' 使用'me/messages'端点。

希望这有帮助。

如果答案对您有帮助,请点击“接受答案” 投票赞成。如果您对此答案还有其他疑问,请 点击“评论”。

另一个答案说:

为了解决此问题,我将租户 ID 替换为关键字 常见于authorizationURL 和tokenURL。这允许用户从 任何 Azure AD 租户,包括个人 Microsoft 帐户, 认证。以下是我的 oAuth 策略代码。

import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { Strategy, VerifyCallback } from 'passport-azure-ad-oauth2';
import { AuthService } from './auth.service';
import { ConfigService } from '@nestjs/config';
import axios from 'axios';

@Injectable()
export class OauthStrategy extends PassportStrategy(Strategy, 'azure-ad') {
  constructor(
    private readonly authService: AuthService,
    private readonly configService: ConfigService
  ) {
    super({
      clientID: this.configService.get<string>('AZURE_CLIENT_ID'),
      clientSecret: this.configService.get<string>('AZURE_CLIENT_SECRET'),
      callbackURL: this.configService.get<string>('AZURE_CALLBACK_URL'),
      authorizationURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
      tokenURL: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
      scope: [
        'openid',
        'User.Read',
        'profile',
        'email',
        'Mail.Read',
        'Mail.ReadBasic',
      ],
    });
  }

  async validate(
    accessToken: string,
    refreshToken: string,
    params: any,
    profile: any,
    done: VerifyCallback
  ): Promise<any> {
    try {
      const userProfile = await this.getUserProfile(accessToken);
      const user = await this.authService.validateUser(userProfile);
      if (!user) {
        throw new UnauthorizedException();
      }
      done(null, user);
    } catch (error) {
      done(error, false);
    }
  }

  async getUserProfile(accessToken: string): Promise<any> {
    const graphUrl = 'https://graph.microsoft.com/v1.0/me';
    const response = await axios.get(graphUrl, {
      headers: {
        Authorization: `Bearer ${accessToken}`,
      },
    });
    return response.data;
  }
}

因此,您需要确保您的租户已做好适当准备,然后您可以像在

"https://login.microsoftonline.com/{$tennantId}/oauth2/v2.0/token?scope={$scope}&client_id={$secretId}"
的 URL 中一样传递它的 id,或者将其中的
{$tennantId}
替换为
common

© www.soinside.com 2019 - 2024. All rights reserved.