You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel+Socialite集成Microsoft账号:无法获取Ads及Merchant Center数据

问题描述

我正在开发一个Laravel项目,使用Socialite实现Microsoft账号的认证与登录。已在Azure门户创建应用,设置“支持的账号类型:所有Microsoft账号用户”,认证流程正常,可成功获取用户ID、姓名、邮箱等基础信息。但无法获取用户的Ads账号和Merchant Center信息,在Azure门户中找不到ads.manage这类所需的API权限/范围,希望了解如何启用这些权限并正确配置Azure应用以获取所需数据。


当前代码实现

Socialite Microsoft Provider扩展代码

namespace SocialiteProviders\Microsoft;

use Illuminate\Support\Arr;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Log;
use GuzzleHttp\Exception\ClientException;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
use SocialiteProviders\Microsoft\MicrosoftUser as User;

class Provider extends AbstractProvider
{
    public const IDENTIFIER = 'MICROSOFT';

    protected const DEFAULT_FIELDS_USER = ['id', 'displayName', 'userPrincipalName'];
    protected const DEFAULT_FIELDS_ADS_ACCOUNTS = ['id', 'name', 'customerId'];
    protected const DEFAULT_FIELDS_MERCHANT_ACCOUNTS = ['id', 'name'];

    protected $scopes = [
        'https://graph.microsoft.com/User.Read',
        'https://ads.microsoft.com/msads.manage',
        'offline_access',
    ];

    protected function getAuthUrl($state)
    {
        return $this->buildAuthUrlFromBase(
            'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
            $state
        );
    }

    protected function getTokenUrl()
    {
        return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
    }

    protected function getUserByToken($token)
    {
        $user = $this->getUserData($token, 'https://graph.microsoft.com/v1.0/me', self::DEFAULT_FIELDS_USER);

        if (!$user) {
            return [];
        }

        try {
            $adsAccounts = $this->getUserData($token, 'https://ads.microsoft.com/api/v13/accounts', self::DEFAULT_FIELDS_ADS_ACCOUNTS);
        } catch (ClientException $e) {
            Log::error('Failed to fetch ads accounts', ['exception' => $e, 'user' => $user]);
            $adsAccounts = [];
        }

        try {
            $merchantAccounts = $this->getUserData($token, 'https://marketing.microsoft.com/rest/v1/merchantcenters', self::DEFAULT_FIELDS_MERCHANT_ACCOUNTS);
        } catch (ClientException $e) {
            Log::error('Failed to fetch merchant accounts', ['exception' => $e, 'user' => $user]);
            $merchantAccounts = [];
        }

        $user['adsAccounts'] = $adsAccounts;
        $user['merchantAccounts'] = $merchantAccounts;

        return $user;
    }

    protected function mapUserToObject(array $user)
    {
        return (new User())->setRaw($user)->map([
            'id' => $user['id'],
            'nickname' => null,
            'name' => $user['displayName'],
            'email' => $user['userPrincipalName'],
            'avatar' => Arr::get($user, 'avatar'),
            'adsAccounts' => Arr::get($user, 'adsAccounts'),
            'merchantAccounts' => Arr::get($user, 'merchantAccounts'),
            'tenant' => Arr::get($user, 'tenant'),
        ]);
    }

    protected function getTokenFields($code)
    {
        return array_merge(parent::getTokenFields($code), [
            'scope' => $this->formatScopes($this->getScopes(), $this->scopeSeparator),
        ]);
    }

    public static function additionalConfigKeys()
    {
        return ['tenant', 'include_tenant_info', 'include_avatar', 'include_avatar_size', 'fields', 'tenant_fields'];
    }

    protected function getUserData($token, $url, $fields)
    {
        $response = $this->getHttpClient()->get($url, [
            RequestOptions::HEADERS => [
                'Accept' => 'application/json',
                'Authorization' => 'Bearer ' . $token,
            ],
            RequestOptions::QUERY => [
                '$select' => implode(',', $fields),
            ],
        ]);

        $data = json_decode((string) $response->getBody(), true);

        if (!$data) {
            return [];
        }

        return $data;
    }
}

Laravel服务配置(config/services.php)

'microsoft' => [
    'client_id' => env('MICROSOFT_CLIENT_ID'),
    'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
    'tenant_id' => env('MICROSOFT_TENANT_ID'),
    'redirect' => env('MICROSOFT_REDIRECT_URI'),
    'tenant' => 'common',
    'include_tenant_info' => true,
],

环境变量(.env)

MICROSOFT_CLIENT_ID=*****
MICROSOFT_CLIENT_SECRET=***
MICROSOFT_TENANT_ID=**
MICROSOFT_REDIRECT_URI=https://infinitemsfeed.com/microsoft/auth

控制器登录逻辑

public function redirectToMicrosoft()
{
    return Socialite::driver('microsoft')->redirect();
}

public function handleMicrosoftCallback()
{
    $user = Socialite::driver('microsoft')->user();

    return $user;
}

前端触发代码

const handleMicrosoftLogin = () => {
  window.open("https://infinitemsfeed.com/auth/microsoft?token=" + window.sessionToken, "_blank")
}

当前Azure API权限配置截图

API权限配置


解决方案

1. 手动添加目标API权限

Azure AD默认不显示Microsoft Ads和Merchant Center的权限,需手动添加:

  • 登录Azure门户,进入目标应用注册页面
  • 左侧菜单选择「API权限」,点击「添加权限」
  • 选择「我的API」→「添加API」,在搜索框输入对应API的应用ID:
    • Microsoft Ads API:1200150d-7368-409c-85f6-617b5788f977
    • Microsoft Merchant Center API:d3590ed6-52b3-4102-aeff-aad2292ab01c
  • 添加后勾选对应委托权限:
    • Microsoft Ads:msads.manage
    • Merchant Center:MerchantCenterManage
  • 点击「添加权限」,若为租户级应用需点击「授予管理员同意」,个人账号可跳过,用户授权时会自动提示

2. 修正权限范围配置

更新Provider类的scopes,补充Merchant Center权限:

protected $scopes = [
    'https://graph.microsoft.com/User.Read',
    'https://ads.microsoft.com/msads.manage',
    'https://marketing.microsoft.com/MerchantCenterManage',
    'offline_access',
];

3. 调整API调用端点

当前代码中的API端点存在错误,修正为官方标准端点:

  • Microsoft Ads API:需先获取用户customerId,再调用https://api.ads.microsoft.com/v13/customers/{customerId}/accounts
  • Merchant Center API:使用https://api.partner.microsoft.com/v1.0/merchant-center/accounts

4. 切换令牌版本

Microsoft Ads API仅支持v1.0令牌,调整Provider的授权与令牌端点:

protected function getAuthUrl($state)
{
    return $this->buildAuthUrlFromBase(
        'https://login.microsoftonline.com/common/oauth2/authorize',
        $state
    );
}

protected function getTokenUrl()
{
    return 'https://login.microsoftonline.com/common/oauth2/token';
}

5. 测试权限获取

重新部署代码后触发登录流程,用户授权时会看到新增的权限请求,授权后即可尝试获取对应账号数据。


内容的提问来源于stack exchange,提问作者Kamal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 05:21:07