> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PlayFab API 的 Microsoft Entra ID 驗證

> 使用 PKCE、裝置代碼或隱含授與等 OAuth 2.0 流程，以 Microsoft Entra ID 委派權杖向 PlayFab Admin、Server 和實體 API 進行驗證。

PlayFab 支援使用 Microsoft Entra ID (先前稱為 Azure Active Directory) 驗證來呼叫 Admin、Server 和實體 API。使用 Entra ID 驗證時，您會以 Microsoft 身分識別登入，並使用委派存取權杖取代開發人員祕密金鑰。您的應用程式會使用標準 OAuth 2.0 公用用戶端流程 (例如具有 PKCE 的授權碼、裝置代碼或隱含授與) 處理登入體驗。

<Note>
  對於 Admin、Server 和部分實體 API 呼叫，Entra ID 驗證是開發人員祕密金鑰的替代方案。面向玩家的 Client 和實體 API 會繼續使用透過玩家登入取得的工作階段票證和實體權杖。只有可使用\_遊戲\_實體權杖呼叫的實體 API 才能搭配 Entra ID 使用。如需祕密金鑰的詳細資訊，請參閱[祕密金鑰管理](/zh-TW/services/playfab/live-service-management/gamemanager/secret-key-management)。
</Note>

## 為何使用 Entra ID 驗證

開發人員祕密金鑰使用簡單，但 Entra ID 驗證提供多項優點：

* **沒有共用祕密**：公用用戶端流程不需要用戶端祕密。權杖為短期有效，且範圍限定於已登入的使用者。
* **個人責任歸屬**：每個 API 呼叫都與特定使用者身分識別綁定，讓您能輕鬆稽核誰做了什麼。
* **條件式存取**：您的組織可以套用 Entra ID 原則，例如 IP 限制、多重要素驗證 (MFA) 和裝置合規性檢查。

## Entra ID 驗證的運作方式

如果您從未使用過 Microsoft Entra ID，它是 Microsoft 的雲端身分識別服務，也是支援 Microsoft 365、XBOX 開發人員帳戶和 Azure 的同一套身分識別系統。PlayFab 不會為您的工作室核發長期有效的祕密金鑰，而是由您的工具要求 Entra ID 讓開發人員登入，並傳回短期有效的**存取權杖**。PlayFab 信任 Entra ID 為您工作室成員的使用者所核發的權杖。

涉及三個角色：

* **開發人員。** 也就是您，以 Microsoft 帳戶 (個人) 或公司或學校帳戶 (Entra ID) 登入。
* **Entra ID 中的應用程式註冊。** 這代表呼叫 PlayFab 的工具，例如 CLI、組建指令碼、內部儀表板等。它會告訴 Entra ID「此應用程式可以代表已登入的使用者要求 PlayFab 存取權杖」。
* **PlayFab 服務。** PlayFab 在 Entra ID 中以應用程式識別碼 `448adbda-b8d8-4f33-a1b0-ac58cf44d4c1` 註冊，並公開名為 `plugin` 的委派權限。當您的程式碼要求範圍 `448adbda-b8d8-4f33-a1b0-ac58cf44d4c1/plugin` 時，Entra ID 會核發 PlayFab 接受的權杖。

典型的呼叫如下所示：

1. 您的程式碼使用 Microsoft 驗證程式庫 (MSAL) 開始登入，通常是瀏覽器快顯視窗或裝置代碼提示。
2. 使用者以其 Microsoft 身分識別登入，並同意您的應用程式代表他們呼叫 PlayFab。
3. MSAL 會傳回存取權杖 (JWT)，並快取重新整理權杖，讓之後的呼叫可以略過提示。
4. 您的程式碼會在每個 PlayFab 要求的 `Authorization: Bearer <token>` 標頭中傳送權杖。
5. PlayFab 會驗證權杖、將其對應至相符的工作室使用者，並根據該使用者的角色授權呼叫。

如需本文中使用的 Entra ID 術語定義，請參閱文末的[詞彙](#glossary)。

## 必要條件

* 以 Entra ID 為後盾的 Microsoft 帳戶 (公司或學校帳戶) 或個人 Microsoft 帳戶 (MSA)。
* PlayFab 遊戲。如需詳細資訊，請參閱[建立 PlayFab 帳戶](/zh-TW/services/playfab/identity/dev-identity/pfab-account)。
* 在您的 Microsoft Entra ID 租用戶中註冊應用程式的權限。
* 呼叫的使用者必須已新增至 PlayFab 工作室，並被指派為遊戲系統管理員。如需角色的詳細資訊，請參閱 [PlayFab 使用者角色](/zh-TW/services/playfab/identity/dev-identity/permissions/playfab-user-roles)。

## 在 Entra ID 中註冊公用用戶端應用程式

您需要在 Entra ID 租用戶中註冊應用程式，讓您的程式碼能代表已登入的使用者要求委派權杖。對於公用用戶端流程 (SPA、裝置代碼、隱含)，不需要用戶端祕密。

1. 登入 [Azure 入口網站](https://portal.azure.com)。

2. 搜尋並選取 **應用程式註冊**，然後選取 **新增註冊**。

3. 輸入您應用程式的名稱 (例如 `PlayFab API Client`)。

4. 在 **支援的帳戶類型** 下，選取符合您組織需求的選項。若要獲得最大彈性，請選取 **任何組織目錄中的帳戶 (任何 Microsoft Entra ID 租用戶 - 多租用戶) 及個人 Microsoft 帳戶**。此選項允許任何 Microsoft 帳戶進行驗證。

5. 根據您的應用程式類型設定 **重新導向 URI**：
   * 對於單頁應用程式 (SPA)，請選取 **單頁應用程式 (SPA)**，並輸入您的重新導向 URI (例如 `http://localhost:3000`)。
   * 對於使用裝置代碼流程的原生或主控台應用程式，請選取 **公用用戶端/原生 (行動和桌面)**，並輸入 `http://localhost`。

6. 選取 **註冊**。在概觀頁面上，記下 **應用程式 (用戶端) 識別碼**。要求權杖時需要此值。

7. 將 PlayFab API 權限新增至您的應用程式註冊：
   1. 在 Azure 入口網站中，瀏覽至您的應用程式註冊，然後選取 **API 權限**。
   2. 選取 **新增權限** > **我的組織使用的 API**。
   3. 搜尋 PlayFab 應用程式識別碼 `448adbda-b8d8-4f33-a1b0-ac58cf44d4c1` 並選取它。
   4. 選取 **委派的權限**，核取 **plugin** 權限，然後選取 **新增權限**。

<Note>
  如果您的案例需要機密 (Web 應用程式) 用戶端，您也需要在 **憑證及祕密** 下建立用戶端祕密。本文著重於不需要祕密的公用用戶端流程。如需機密用戶端流程的詳細資訊，請參閱 [Microsoft 身分識別平台和 OAuth 2.0 授權碼流程](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow)。
</Note>

## 設定 PlayFab 工作室存取權

PlayFab 會根據工作室成員資格驗證 Entra ID 權杖。呼叫的使用者必須已新增至 PlayFab 工作室，並獲授與適當的角色。

1. 請工作室系統管理員登入 [Game Manager](https://developer.playfab.com)。

2. 瀏覽至工作室的 **使用者** 區段。

3. 選取 **新增使用者**，並輸入需要 API 存取權之開發人員的 Microsoft 帳戶電子郵件。

4. 選取 **Microsoft** 作為驗證提供者。

5. 為使用者指派包含 Admin 或 Server API 存取權的角色。使用者至少必須是其需要呼叫 API 之遊戲的 **遊戲系統管理員**。

6. 選取 **新增使用者** 以傳送邀請。

如需新增使用者和指派角色的詳細資訊，請參閱 [PlayFab Game Manager 的帳戶驗證](/zh-TW/services/playfab/identity/dev-identity/authentication/aad-authentication)。

## 取得存取權杖

您的應用程式負責讓使用者登入，並從 Entra ID 取得委派存取權杖。下列範例顯示常見的公用用戶端流程。

### 互動式瀏覽器流程 (建議用於桌面和主控台應用程式)

互動式瀏覽器流程會開啟系統瀏覽器視窗以進行登入。這是桌面應用程式和本機開發工具的建議選項。

```csharp theme={null}
using Microsoft.Identity.Client;

// Build an MSAL public client app. The client ID identifies your Entra app
// registration; "common" lets users sign in from any Entra tenant or with a
// personal Microsoft account.
var app = PublicClientApplicationBuilder.Create("your-client-id")
    .WithAuthority("https://login.microsoftonline.com/common")
    .WithDefaultRedirectUri()
    .Build();

// The scope identifies the PlayFab API and the delegated permission ("plugin")
// your app is requesting on behalf of the signed-in user.
string[] scopes = ["448adbda-b8d8-4f33-a1b0-ac58cf44d4c1/plugin"];

AuthenticationResult result;
try
{
    // Try to get a token from MSAL's cache without prompting the user.
    // This succeeds on subsequent runs while the cached refresh token is valid.
    var accounts = await app.GetAccountsAsync();
    result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
        .ExecuteAsync();
}
catch (MsalUiRequiredException)
{
    // No cached token, or it expired and can't be refreshed silently.
    // Open the system browser so the user can sign in interactively.
    result = await app.AcquireTokenInteractive(scopes)
        .WithUseEmbeddedWebView(false)
        .ExecuteAsync();
}

// The access token is what you send to PlayFab in the Authorization header.
string accessToken = result.AccessToken;
```

### 具有 PKCE 的授權碼 (建議用於 SPA)

具有程式碼交換證明金鑰 (PKCE) 的授權碼流程是單頁應用程式的建議方法。下列 JavaScript 範例使用 Microsoft 驗證程式庫 (MSAL)：

```javascript theme={null}
import { PublicClientApplication } from "@azure/msal-browser";

// MSAL config. clientId is your Entra app registration's Application (client) ID.
// "common" lets users sign in from any tenant or with a personal account.
// redirectUri must match a Single-page application redirect URI on the app registration.
const msalConfig = {
    auth: {
        clientId: "your-client-id",
        authority: "https://login.microsoftonline.com/common",
        redirectUri: "http://localhost:3000"
    }
};

const msalInstance = new PublicClientApplication(msalConfig);
await msalInstance.initialize();

// loginPopup runs the auth code + PKCE flow in a pop-up window. The scope
// asks Entra ID for a delegated token that PlayFab will accept.
const loginResponse = await msalInstance.loginPopup({
    scopes: ["448adbda-b8d8-4f33-a1b0-ac58cf44d4c1/plugin"]
});

// Send this token to PlayFab in the Authorization header.
const accessToken = loginResponse.accessToken;
```

## 使用存取權杖呼叫 PlayFab API

在您的 PlayFab API 要求中，將 Entra ID 存取權杖以 Bearer 權杖的形式包含在 `Authorization` 標頭中，而不是使用 `X-SecretKey` 標頭。

### 範例要求

```http theme={null}
POST https://{titleId}.playfabapi.com/Server/GetPlayerProfile
Content-Type: application/json
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOi...

{
    "PlayFabId": "ABCDEF1234567890"
}
```

<Note>
  您不能在同一個要求中同時使用 `X-SecretKey` 和 `Authorization: Bearer`。每個呼叫請使用一種驗證方法。
</Note>

### C# 範例

下列範例使用 Microsoft 驗證程式庫 (MSAL) 取得權杖，並呼叫 `Server/GetTime` API。請將 `your-client-id` 取代為您應用程式註冊中的 **應用程式 (用戶端) 識別碼**。

```csharp theme={null}
using Microsoft.Identity.Client;
using System.Net.Http.Headers;
using System.Text;

// PlayFab API endpoint. Every title gets its own subdomain on playfabapi.com.
string titleId = "YOUR_TITLE_ID";
string host = $"{titleId}.playfabapi.com";
string url = $"https://{host}/Server/GetTime";

// MSAL configuration.
// clientId   - your Entra app registration's Application (client) ID.
// authority  - "common" lets any Entra tenant or personal Microsoft account sign in.
// scopes     - the PlayFab application ID + the "plugin" delegated permission.
string clientId = "your-client-id";
string authority = "https://login.microsoftonline.com/common";
string[] scopes = ["448adbda-b8d8-4f33-a1b0-ac58cf44d4c1/plugin"];

// Build the MSAL public client. Public clients (desktop, CLI, mobile) don't use
// a client secret; tokens are bound to the signed-in user instead.
var app = PublicClientApplicationBuilder.Create(clientId)
    .WithAuthority(authority)
    .WithDefaultRedirectUri()
    .Build();

AuthenticationResult authResult;
try
{
    // Reuse a cached token if MSAL has one. Avoids prompting on every run.
    var accounts = await app.GetAccountsAsync();
    authResult = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
        .ExecuteAsync();
}
catch (MsalUiRequiredException)
{
    // First run, or the cached token expired. Open the system browser to sign in.
    authResult = await app.AcquireTokenInteractive(scopes)
        .WithUseEmbeddedWebView(false)
        .ExecuteAsync();
}

// Call PlayFab. Replace X-SecretKey with an Authorization: Bearer header
// containing the Entra ID access token.
using var httpClient = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
request.Content = new StringContent("{}", Encoding.UTF8, "application/json");

var response = await httpClient.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

Console.WriteLine($"Status: {response.StatusCode}");
Console.WriteLine($"Response: {body}");
```

### Node.js 範例

下列範例使用 `@azure/msal-node` 程式庫取得權杖，並呼叫 `Server/GetTime` API。請將 `your-client-id` 取代為您應用程式註冊中的 **應用程式 (用戶端) 識別碼**。

```javascript theme={null}
import { PublicClientApplication } from "@azure/msal-node";
import open from "open";

// PlayFab API endpoint for your title.
const titleId = "YOUR_TITLE_ID";
const host = `${titleId}.playfabapi.com`;
const url = `https://${host}/Server/GetTime`;

// MSAL configuration.
// clientId  - your Entra app registration's Application (client) ID.
// authority - "common" accepts any Entra tenant or personal Microsoft account.
const msalConfig = {
    auth: {
        clientId: "your-client-id",
        authority: "https://login.microsoftonline.com/common",
    },
};

const pca = new PublicClientApplication(msalConfig);

// Token request:
// scopes      - PlayFab application ID + the "plugin" delegated permission.
// redirectUri - must match a Public client redirect URI on the app registration.
// openBrowser - MSAL calls this to launch the user's default browser for sign-in.
const tokenRequest = {
    scopes: ["448adbda-b8d8-4f33-a1b0-ac58cf44d4c1/plugin"],
    redirectUri: "http://localhost:3000",
    openBrowser: async (url) => { await open(url); },
    successTemplate: "<h1>Authentication complete. You can close this window.</h1>",
};

// Sign the user in and obtain a delegated access token.
const authResult = await pca.acquireTokenInteractive(tokenRequest);

// Call PlayFab with the token in the Authorization header instead of X-SecretKey.
const response = await fetch(url, {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${authResult.accessToken}`,
    },
    body: JSON.stringify({}),
});

const body = await response.json();
console.log(`Status: ${response.status}`);
console.log("Response:", JSON.stringify(body, null, 2));
```

## 權杖重新整理

Entra ID 存取權杖為短期有效 (通常為 60–90 分鐘)。如果您使用 MSAL，請在每個要求之前呼叫 `AcquireTokenSilent` (C#) 或檢查權杖快取。當有可用的快取重新整理權杖時，MSAL 會自動處理重新整理。

如果您手動管理權杖，請在目前權杖到期之前，使用相同的登入流程要求新權杖。

<Info>
  如果權杖在使用期間到期，PlayFab 會傳回 `401 Unauthorized` 回應。您的應用程式應透過要求新權杖並重試呼叫來處理此錯誤。
</Info>

## 疑難排解

| 問題 | 原因 | 解決方式 |
| - | - | - |
| `401 Unauthorized` | 權杖已過期或無效 | 重新登入並要求新權杖 |
| `403 Forbidden` | 使用者在該遊戲上沒有必要的角色 | 在 Game Manager 中確認工作室成員資格和遊戲系統管理員角色 |
| `AADSTS50076: Need multifactor authentication` | 條件式存取原則需要 MFA | 完成 MFA 挑戰並重試 |
| `AADSTS700016: Application not found` | 用戶端識別碼不正確，或應用程式不在預期的租用戶中 | 確認用戶端識別碼和租用戶識別碼 |

### 範例錯誤回應

當 Bearer 權杖遺失、格式不正確或已過期時，PlayFab 傳回的 `401 Unauthorized` 如下所示：

```json theme={null}
{
    "code": 401,
    "status": "Unauthorized",
    "error": "NotAuthenticated",
    "errorCode": 1074,
    "errorMessage": "Invalid \"Authorization\" header."
}
```

當已登入的使用者已通過驗證，但缺少該遊戲的系統管理員權限時，PlayFab 傳回的 `403 Forbidden` 如下所示：

```json theme={null}
{
    "code": 403,
    "status": "Forbidden",
    "error": "NotAuthorizedByTitle",
    "errorCode": 1191,
    "errorMessage": "Developer does not have admin permission for this title."
}
```

## 限制

PlayFab SDK 目前不支援 Entra ID 驗證。若要現在使用 Entra ID 權杖呼叫 PlayFab API，請使用直接 HTTP 呼叫並自行設定 `Authorization: Bearer <token>` 標頭，如 [C#](#c-example) 和 [Node.js](#nodejs-example) 範例所示。SDK 支援已規劃於未來版本中推出。

## 詞彙

| 術語 | 意義 |
| - | - |
| **租用戶** | Entra ID 中的隔離目錄。您的公司有一個；個人 Microsoft 帳戶使用名為 *consumers* 的共用租用戶。範例中使用的 `common` 授權單位可讓使用者從任何租用戶登入。 |
| **應用程式註冊** | Entra ID 中描述您用戶端應用程式的記錄 (其用戶端識別碼、允許的重新導向 URI、要求的 API 權限)。 |
| **委派的權限** | 您的應用程式*代表*已登入使用者所獲得的權限，而非以應用程式本身身分運作。 |
| **公用用戶端** | 無法安全儲存祕密的用戶端，例如桌面或行動應用程式、CLI 或單頁 Web 應用程式。公用用戶端使用具有 PKCE 的授權碼或裝置代碼等流程，而非用戶端祕密。 |
| **範圍** | 您的程式碼向 Entra ID 要求的 API 權限。對於 PlayFab，範圍為 `448adbda-b8d8-4f33-a1b0-ac58cf44d4c1/plugin`。 |
| **MSAL** | Microsoft 驗證程式庫。實作所有這些流程的官方用戶端程式庫，讓您不必手動建構 OAuth 要求。 |

## 另請參閱

* [祕密金鑰管理](/zh-TW/services/playfab/live-service-management/gamemanager/secret-key-management)
* [PlayFab Game Manager 的帳戶驗證](/zh-TW/services/playfab/identity/dev-identity/authentication/aad-authentication)
* [PlayFab 使用者角色](/zh-TW/services/playfab/identity/dev-identity/permissions/playfab-user-roles)
* [API 存取原則](/zh-TW/services/playfab/api-references/api-access-policy)
* [Microsoft Entra ID 文件](https://learn.microsoft.com/en-us/entra/fundamentals/whatis)


## Related topics

- [PlayFab 的 Microsoft 帳戶驗證](/zh-TW/services/playfab/identity/dev-identity/authentication/aad-authentication.md)
- [將 Grafana 連線至 Insights](/zh-TW/services/playfab/data-analytics/legacy/connectivity/connecting-grafana-to-insights.md)
- [為 PlayFab Insights 建立 Microsoft Entra ID 應用程式](/zh-TW/services/playfab/data-analytics/legacy/connectivity/creating-AAD-app-for-insights.md)
- [驗證](/zh-TW/services/playfab/identity/player-identity/authentication/index.md)
- [市集整合 - Microsoft Store](/zh-TW/services/playfab/economy-monetization/economy-v2/marketplace/marketplace-integrations/microsoft.md)
