Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Använd Microsoft Entra ID Auth SDK (sidovagn) för att hantera både tokenförvärv och HTTP-kommunikation i en enda åtgärd. SDK:n byter ut din inkommande token mot en som är begränsad till det underordnade API:et och gör sedan HTTP-anropet och returnerar svaret. Den här guiden visar hur du konfigurerar underordnade API:er, implementerar anrop i TypeScript och Python, hanterar olika HTTP-metoder och hanterar fel med återförsök.
Förutsättningar
- Ett Azure konto med en aktiv prenumeration. Skapa ett konto kostnadsfritt.
- Microsoft Entra ID Auth SDK (sidecar) är distribuerad och körs i din miljö. Se Installationsguide för installationsinstruktioner.
- Downstream API konfigureras i SDK med den grundläggande URL:en och de nödvändiga omfången för API:erna som du vill anropa.
- Ägartoken från autentiserade klienter – Ditt program tar emot token från klientprogram som du vidarebefordrar till SDK: et.
- Lämpliga behörigheter i Microsoft Entra ID – Ditt konto måste ha behörigheter för att registrera program och bevilja API-behörigheter.
Konfiguration
Konfigurera det underordnade API:et i miljöinställningarna för Microsoft Entra ID Auth SDK (sidovagn):
env:
- name: DownstreamApis__Graph__BaseUrl
value: "https://graph.microsoft.com/v1.0"
- name: DownstreamApis__Graph__Scopes__0
value: "User.Read"
- name: DownstreamApis__Graph__Scopes__1
value: "Mail.Read"
Konfigurationen anger:
- BaseUrl: Rotslutpunkten för ditt underordnade API
- Omfång: De behörigheter som krävs för åtkomst till det underordnade API:et
TypeScript/Node.js
I följande exempel visas hur du anropar underordnade API:er från TypeScript och Node.js program. Koden visar både en återanvändbar funktion och integrering med Express.js.
interface DownstreamApiResponse {
statusCode: number;
headers: Record<string, string>;
content: string;
}
async function callDownstreamApi(
incomingToken: string,
serviceName: string,
relativePath: string,
method: string = 'GET',
body?: any
): Promise<any> {
const sdkUrl = process.env.ENTRA_SDK_URL || 'http://localhost:5000';
const url = new URL(`${sdkUrl}/DownstreamApi/${serviceName}`);
url.searchParams.append('optionsOverride.RelativePath', relativePath);
if (method !== 'GET') {
url.searchParams.append('optionsOverride.HttpMethod', method);
}
const requestOptions: any = {
method: method,
headers: {
'Authorization': incomingToken
}
};
if (body) {
requestOptions.headers['Content-Type'] = 'application/json';
requestOptions.body = JSON.stringify(body);
}
const response = await fetch(url.toString(), requestOptions);
if (!response.ok) {
throw new Error(`SDK error: ${response.statusText}`);
}
const data = await response.json() as DownstreamApiResponse;
if (data.statusCode >= 400) {
throw new Error(`API error ${data.statusCode}: ${data.content}`);
}
return JSON.parse(data.content);
}
// Usage examples
async function getUserProfile(incomingToken: string) {
return await callDownstreamApi(incomingToken, 'Graph', 'me');
}
async function listEmails(incomingToken: string) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me/messages?$top=10&$select=subject,from,receivedDateTime'
);
}
async function sendEmail(incomingToken: string, message: any) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me/sendMail',
'POST',
{ message }
);
}
I följande exempel visas hur du integrerar dessa funktioner i ett Express.js program med mellanprogram och routningshanterare:
// Express.js API example
import express from 'express';
const app = express();
app.use(express.json());
app.get('/api/profile', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token' });
}
const profile = await getUserProfile(incomingToken);
res.json(profile);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Failed to fetch profile' });
}
});
app.get('/api/messages', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token' });
}
const messages = await listEmails(incomingToken);
res.json(messages);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Failed to fetch messages' });
}
});
app.post('/api/messages/send', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token' });
}
const message = req.body;
await sendEmail(incomingToken, message);
res.json({ success: true });
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Failed to send message' });
}
});
app.listen(8080, () => {
console.log('Server running on port 8080');
});
Python
I följande exempel visas hur du anropar underordnade API:er från Python program med hjälp av begärandebiblioteket och Flask för HTTP-hantering:
import os
import json
import requests
from typing import Dict, Any, Optional
def call_downstream_api(
incoming_token: str,
service_name: str,
relative_path: str,
method: str = 'GET',
body: Optional[Dict[str, Any]] = None
) -> Any:
"""Call a downstream API via the Microsoft Entra ID Auth SDK (sidecar)."""
sdk_url = os.getenv('ENTRA_SDK_URL', 'http://localhost:5000')
params = {
'optionsOverride.RelativePath': relative_path
}
if method != 'GET':
params['optionsOverride.HttpMethod'] = method
headers = {'Authorization': incoming_token}
json_body = None
if body:
headers['Content-Type'] = 'application/json'
json_body = body
response = requests.request(
method,
f"{sdk_url}/DownstreamApi/{service_name}",
params=params,
headers=headers,
json=json_body
)
if not response.ok:
raise Exception(f"SDK error: {response.text}")
data = response.json()
if data['statusCode'] >= 400:
raise Exception(f"API error {data['statusCode']}: {data['content']}")
return json.loads(data['content'])
# Usage examples
def get_user_profile(incoming_token: str) -> Dict[str, Any]:
return call_downstream_api(incoming_token, 'Graph', 'me')
def list_emails(incoming_token: str) -> Dict[str, Any]:
return call_downstream_api(
incoming_token,
'Graph',
'me/messages?$top=10&$select=subject,from,receivedDateTime'
)
def send_email(incoming_token: str, message: Dict[str, Any]) -> None:
call_downstream_api(
incoming_token,
'Graph',
'me/sendMail',
'POST',
{'message': message}
)
Om du vill integrera dessa funktioner i ett Flask-program kan du använda följande exempel:
# Flask API example
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/profile')
def profile():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token'}), 401
try:
profile_data = get_user_profile(incoming_token)
return jsonify(profile_data)
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Failed to fetch profile'}), 500
@app.route('/api/messages')
def messages():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token'}), 401
try:
messages_data = list_emails(incoming_token)
return jsonify(messages_data)
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Failed to fetch messages'}), 500
@app.route('/api/messages/send', methods=['POST'])
def send_message():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token'}), 401
try:
message = request.json
send_email(incoming_token, message)
return jsonify({'success': True})
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Failed to send message'}), 500
if __name__ == '__main__':
app.run(port=8080)
POST/PUT/PATCH-begäranden
Slutpunkten /DownstreamApi stöder ändringsåtgärder genom att skicka HTTP-metoden och begärandetexten. Använd dessa mönster när du behöver skapa, uppdatera eller ta bort resurser i det underordnade API:et.
Skapa resurser
// POST example - Create a calendar event
async function createEvent(incomingToken: string, event: any) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me/events',
'POST',
event
);
}
// Usage
const newEvent = {
subject: "Team Meeting",
start: {
dateTime: "2024-01-15T14:00:00",
timeZone: "Pacific Standard Time"
},
end: {
dateTime: "2024-01-15T15:00:00",
timeZone: "Pacific Standard Time"
}
};
const createdEvent = await createEvent(incomingToken, newEvent);
Uppdatera resurser
// PATCH example - Update user profile
async function updateProfile(incomingToken: string, updates: any) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me',
'PATCH',
updates
);
}
// Usage
await updateProfile(incomingToken, {
mobilePhone: "+1 555 0100",
officeLocation: "Building 2, Room 201"
});
Avancerade scenarier
Följande scenarier visar avancerade konfigurationer för specialiserade användningsfall.
Anpassade rubriker
Lägg till anpassade rubriker i den underordnade API-begäran:
const url = new URL(`${sdkUrl}/DownstreamApi/MyApi`);
url.searchParams.append('optionsOverride.RelativePath', 'items');
url.searchParams.append('optionsOverride.CustomHeader.X-Custom-Header', 'custom-value');
url.searchParams.append('optionsOverride.CustomHeader.X-Request-Id', requestId);
Åsidosätt områden
Begär andra omfång än de standardkonfigurerade omfången:
const url = new URL(`${sdkUrl}/DownstreamApi/Graph`);
url.searchParams.append('optionsOverride.RelativePath', 'me');
url.searchParams.append('optionsOverride.Scopes', 'User.ReadWrite');
url.searchParams.append('optionsOverride.Scopes', 'Mail.Send');
Med agentidentitet
Använd agentidentitet för att anropa API:er med programbehörigheter:
const url = new URL(`${sdkUrl}/DownstreamApi/Graph`);
url.searchParams.append('optionsOverride.RelativePath', 'users');
url.searchParams.append('AgentIdentity', agentClientId);
url.searchParams.append('AgentUsername', 'admin@contoso.com');
Felhantering
Implementera logik för återförsök med exponentiell backoff för att hantera tillfälliga fel på ett korrekt sätt:
async function callDownstreamApiWithRetry(
incomingToken: string,
serviceName: string,
relativePath: string,
method: string = 'GET',
body?: any,
maxRetries: number = 3
): Promise<any> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await callDownstreamApi(
incomingToken,
serviceName,
relativePath,
method,
body
);
} catch (error) {
lastError = error as Error;
// Don't retry on client errors (4xx)
if (error.message.includes('API error 4')) {
throw error;
}
// Retry on server errors (5xx) or network errors
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 100;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw new Error(`Failed after ${maxRetries} retries: ${lastError!.message}`);
}
Jämförelse med AuthorizationHeader-metoden
Microsoft Entra ID Auth SDK (sidovagn) innehåller två metoder för att anropa underordnade API:er. Använd den här jämförelsen för att avgöra vilken metod som passar bäst för dina behov.
Jämförelse av funktioner
| Capability | /DownstreamApi | /AuthorizationHeader |
|---|---|---|
| Tokenförvärv | Hanteras av SDK | Hanteras av SDK |
| HTTP-begäran | Hanteras av SDK | Ditt ansvar |
| Svarsparsning | Omsluten i JSON | Direkt HTTP-svar |
| Anpassade rubriker | Via frågeparametrar | Fullständig HTTP-kontroll |
| Begärandekropp | Vidarebefordras automatiskt | Fullständig kontroll |
| Felhantering | Fel omslutna av SDK | Standard-HTTP-fel |
När du ska använda varje metod
| Användningsfall | Recommendation | Bäst för |
|---|---|---|
| Standardiserade REST-API-anrop med konventionella mönster | /DownstreamApi |
GET, POST, PUT, PATCH, DELETE-operationer och minska standardkoden |
| Komplexa HTTP-klienter som kräver anpassad konfiguration | /AuthorizationHeader |
Specialiserad hantering av begäran/svar; detaljerad kontroll |
| Direktåtkomst till HTTP-felkoder och -huvuden som behövs | /AuthorizationHeader |
Program som behöver http-beteendekontroll på låg nivå |
| Enkelhet och snabb integrering prioriteras | /DownstreamApi |
Program som prioriterar enkelhet framför lågnivåkontroll |
Metodtips
- Återanvända HTTP-klienter: Skapa en gång och återanvänd för att undvika anslutningskostnader
- Implementera felhantering: Lägg till logik för återförsök för tillfälliga fel med exponentiell backoff
- Kontrollera statuskoder: Kontrollera alltid statuskoden innan du parsar svarsinnehållet
- Ange tidsgränser: Konfigurera lämpliga tidsgränser för begäranden för att förhindra hängande begäranden
- Inkludera korrelations-ID: Logga alla begäranden med unika identifierare för spårning från slutpunkt till slutpunkt
- Verifiera indata: Sanera och verifiera data innan de skickas till underordnade API:er
- Övervaka prestanda: Spåra svarstid för API-anrop och felfrekvenser för observerbarhet