Bearbeiten eines Profils in einer Node.js-Web-App
Gilt für: Mitarbeitermandanten Externe Mandanten (weitere Informationen)
Dieser Artikel ist Teil 2 einer Reihe, die veranschaulicht, wie die Profilbearbeitungslogik in einer Node.js Web-App hinzugefügt wird. In Teil 1 dieser Reihe richten Sie Ihre App für die Profilbearbeitung ein.
In diesem Leitfaden erfahren Sie, wie Sie die Microsoft Graph-API für die Profilbearbeitung aufrufen.
Voraussetzungen
- Führen Sie die Schritte im zweiten Teil dieser Anleitungsreihe aus, und richten Sie eine Node.js Webanwendung für die Profilbearbeitung ein.
Abschließen der Clientweb-App
In diesem Abschnitt fügen Sie den identitätsbezogenen Code für die Clientweb-App hinzu.
Aktualisieren der „authConfig.js“-Datei
Aktualisieren Sie die authConfig.js-Datei für die Clientweb-App:
Öffnen Sie in Ihrem Code-Editor die Datei "App/authConfig.js", und fügen Sie dann drei neue Variablen hinzu,
GRAPH_API_ENDPOINT
GRAPH_ME_ENDPOINT
und fügen Sie dann drei neue Variablen hinzueditProfileScope
. Stellen Sie sicher, dass Sie die drei Variablen exportieren://... const GRAPH_API_ENDPOINT = process.env.GRAPH_API_ENDPOINT || "https://graph.microsoft.com/"; // https://learn.microsoft.com/graph/api/user-update?tabs=http const GRAPH_ME_ENDPOINT = GRAPH_API_ENDPOINT + "v1.0/me"; const editProfileScope = process.env.EDIT_PROFILE_FOR_CLIENT_WEB_APP || 'api://{clientId}/EditProfileService.ReadWrite'; module.exports = { //... editProfileScope, GRAPH_API_ENDPOINT, GRAPH_ME_ENDPOINT, //... };
Die
editProfileScope
Variable stellt eine MFA-geschützte Ressource dar, d. h. die Mid-Tier-App (EditProfileService-App).GRAPH_ME_ENDPOINT
ist der Microsoft Graph-API-Endpunkt.
Ersetzen Sie den Platzhalter
{clientId}
durch die Anwendungs-ID (Client-ID) der Mid-Tier-App (EditProfileService-App), die Sie zuvor registriert haben.
Abrufen eines Zugriffstokens in der Clientweb-App
Öffnen Sie in Ihrem Code-Editor die Datei "App/auth/AuthProvider.js ", und aktualisieren Sie dann die getToken
Methode in der AuthProvider
Klasse:
class AuthProvider {
//...
getToken(scopes, redirectUri = "http://localhost:3000/") {
return async function (req, res, next) {
const msalInstance = authProvider.getMsalInstance(authProvider.config.msalConfig);
try {
msalInstance.getTokenCache().deserialize(req.session.tokenCache);
const silentRequest = {
account: req.session.account,
scopes: scopes,
};
const tokenResponse = await msalInstance.acquireTokenSilent(silentRequest);
req.session.tokenCache = msalInstance.getTokenCache().serialize();
req.session.accessToken = tokenResponse.accessToken;
next();
} catch (error) {
if (error instanceof msal.InteractionRequiredAuthError) {
req.session.csrfToken = authProvider.cryptoProvider.createNewGuid();
const state = authProvider.cryptoProvider.base64Encode(
JSON.stringify({
redirectTo: redirectUri,
csrfToken: req.session.csrfToken,
})
);
const authCodeUrlRequestParams = {
state: state,
scopes: scopes,
};
const authCodeRequestParams = {
state: state,
scopes: scopes,
};
authProvider.redirectToAuthCodeUrl(
req,
res,
next,
authCodeUrlRequestParams,
authCodeRequestParams,
msalInstance
);
}
next(error);
}
};
}
}
//...
Die getToken
Methode verwendet den angegebenen Bereich, um ein Zugriffstoken abzurufen. Der redirectUri
-Parameter ist die Umleitungs-URL, nachdem die App ein Zugriffstoken abgerufen hat.
Aktualisieren der „users.js“-Datei
Öffnen Sie in Ihrem Code-Editor die Datei "App/routes/users.js ", und fügen Sie dann die folgenden Routen hinzu:
//...
var { fetch } = require("../fetch");
const { GRAPH_ME_ENDPOINT, editProfileScope } = require('../authConfig');
//...
router.get(
"/gatedUpdateProfile",
isAuthenticated,
authProvider.getToken(["User.Read"]), // check if user is authenticated
async function (req, res, next) {
const graphResponse = await fetch(
GRAPH_ME_ENDPOINT,
req.session.accessToken,
);
if (!graphResponse.id) {
return res
.status(501)
.send("Failed to fetch profile data");
}
res.render("gatedUpdateProfile", {
profile: graphResponse,
});
},
);
router.get(
"/updateProfile",
isAuthenticated, // check if user is authenticated
authProvider.getToken(
["User.Read", editProfileScope],
"http://localhost:3000/users/updateProfile",
),
async function (req, res, next) {
const graphResponse = await fetch(
GRAPH_ME_ENDPOINT,
req.session.accessToken,
);
if (!graphResponse.id) {
return res
.status(501)
.send("Failed to fetch profile data");
}
res.render("updateProfile", {
profile: graphResponse,
});
},
);
router.post(
"/update",
isAuthenticated,
authProvider.getToken([editProfileScope]),
async function (req, res, next) {
try {
if (!!req.body) {
let body = req.body;
fetch(
"http://localhost:3001/updateUserInfo",
req.session.accessToken,
"POST",
{
displayName: body.displayName,
givenName: body.givenName,
surname: body.surname,
},
)
.then((response) => {
if (response.status === 204) {
return res.redirect("/");
} else {
next("Not updated");
}
})
.catch((error) => {
console.log("error,", error);
});
} else {
throw { error: "empty request" };
}
} catch (error) {
next(error);
}
},
);
//...
Sie lösen die
/gatedUpdateProfile
Route aus, wenn der Benutzer des Kunden den Profilbearbeitungslink auswählt. Die App erfüllt diese Funktionen:- Erwirbt ein Zugriffstoken mit der Berechtigung "User.Read ".
- Ruft die Microsoft Graph-API auf, um das Profil des angemeldeten Benutzers zu lesen.
- Zeigt die Benutzerdetails auf der gatedUpdateProfile.hbs-Benutzeroberfläche an.
Sie lösen die
/updateProfile
Route aus, wenn der Benutzer seinen Anzeigenamen aktualisieren möchte, d. h. er wählt die Schaltfläche "Profil bearbeiten" aus. Die App erfüllt diese Funktionen:- Ruft die Mid-Tier-App (EditProfileService-App) mit editProfileScope-Bereich auf. Durch einen Aufruf an die Mid-Tier-App (EditProfileService-App) muss der Benutzer eine MFA-Abfrage ausführen, sofern dies noch nicht geschehen ist.
- Zeigt die Benutzerdetails auf der updateProfile.hbs-Benutzeroberfläche an.
Sie lösen die
/update
-Route aus, wenn der Benutzer die Schaltfläche Speichern entweder in gatedUpdateProfile.hbs oder updateProfile.hbs auswählt. Die App erfüllt diese Funktionen:- Ruft das Zugriffstoken für die App-Sitzung ab. Sie erfahren, wie die Mid-Tier-App (EditProfileService-App) das Zugriffstoken im nächsten Abschnitt erwirbt.
- Sammelt alle Benutzerdetails.
- Ruft die Microsoft Graph-API auf, um das Profil des Benutzers zu aktualisieren.
Aktualisieren der „fetch.js“-Datei
Die App verwendet die Datei "App/fetch.js ", um die tatsächlichen API-Aufrufe vorzunehmen.
Öffnen Sie in Ihrem Code-Editor die Datei "App/fetch.js ", und fügen Sie dann die OPTION PATCH-Vorgang hinzu. Nachdem Sie die Datei aktualisiert haben, sollte die resultierende Datei dem folgenden Code ähneln:
var axios = require('axios');
var authProvider = require("./auth/AuthProvider");
/**
* Makes an Authorization "Bearer" request with the given accessToken to the given endpoint.
* @param endpoint
* @param accessToken
* @param method
*/
const fetch = async (endpoint, accessToken, method = "GET", data = null) => {
const options = {
headers: {
Authorization: `Bearer ${accessToken}`,
},
};
console.log(`request made to ${endpoint} at: ` + new Date().toString());
switch (method) {
case 'GET':
const response = await axios.get(endpoint, options);
return await response.data;
case 'POST':
return await axios.post(endpoint, data, options);
case 'DELETE':
return await axios.delete(endpoint + `/${data}`, options);
case 'PATCH':
return await axios.patch(endpoint, ReqBody = data, options);
default:
return null;
}
};
module.exports = { fetch };
Abschließen der Mid-Tier-App
In diesem Abschnitt fügen Sie den identitätsbezogenen Code für die Mid-Tier-App (EditProfileService-App) hinzu.
Öffnen Sie in Ihrem Code-Editor die Datei "API/authConfig.js ", und fügen Sie dann den folgenden Code hinzu:
require("dotenv").config({ path: ".env.dev" }); const TENANT_SUBDOMAIN = process.env.TENANT_SUBDOMAIN || "Enter_the_Tenant_Subdomain_Here"; const TENANT_ID = process.env.TENANT_ID || "Enter_the_Tenant_ID_Here"; const REDIRECT_URI = process.env.REDIRECT_URI || "http://localhost:3000/auth/redirect"; const POST_LOGOUT_REDIRECT_URI = process.env.POST_LOGOUT_REDIRECT_URI || "http://localhost:3000"; /** * Configuration object to be passed to MSAL instance on creation. * For a full list of MSAL Node configuration parameters, visit: * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-node/docs/configuration.md */ const msalConfig = { auth: { clientId: process.env.CLIENT_ID || "Enter_the_Edit_Profile_Service_Application_Id_Here", // 'Application (client) ID' of the Edit_Profile Service App registration in Microsoft Entra admin center - this value is a GUID authority: process.env.AUTHORITY || `https://${TENANT_SUBDOMAIN}.ciamlogin.com/`, // Replace the placeholder with your external tenant name }, system: { loggerOptions: { loggerCallback(loglevel, message, containsPii) { console.log(message); }, piiLoggingEnabled: false, logLevel: "Info", }, }, }; const GRAPH_API_ENDPOINT = process.env.GRAPH_API_ENDPOINT || "graph_end_point"; // Refers to the user that is single user singed in. // https://learn.microsoft.com/en-us/graph/api/user-update?tabs=http const GRAPH_ME_ENDPOINT = GRAPH_API_ENDPOINT + "v1.0/me"; module.exports = { msalConfig, REDIRECT_URI, POST_LOGOUT_REDIRECT_URI, TENANT_SUBDOMAIN, GRAPH_API_ENDPOINT, GRAPH_ME_ENDPOINT, TENANT_ID, };
Suchen Sie den folgenden Platzhalter:
Enter_the_Tenant_Subdomain_Here
und ersetzen Sie sie durch die Unterdomäne "Verzeichnis(Mandant)". Wenn Ihre primäre Mandantendomäne beispielsweisecontoso.onmicrosoft.com
lautet, verwenden Siecontoso
. Wenn Sie Ihren Mandantennamen nicht kennen, erfahren Sie hier, wie Sie Ihre Mandantendetails auslesen.Enter_the_Tenant_ID_Here
und ersetzen Sie sie durch Mandanten-ID. Wenn Sie nicht über Ihre Mandanten-ID verfügen, erfahren Sie, wie Sie Ihre Mandantendetails lesen.Enter_the_Edit_Profile_Service_Application_Id_Here
und ersetzen Sie ihn durch den Wert der Anwendungs-ID (Client) des zuvor registrierten EditProfileService.Enter_the_Client_Secret_Here
und ersetzen Sie ihn durch den geheimen Wert der EditProfileService-App, den Sie zuvor kopiert haben.graph_end_point
, und ersetzen Sie sie durch den Microsoft Graph-API-Endpunkt,https://graph.microsoft.com/
.
Öffnen Sie in Ihrem Code-Editor die Datei "API/fetch.js ", und fügen Sie dann den Code aus der Api/fetch.js-Datei ein. Die
fetch
Funktion verwendet ein Zugriffstoken und den Ressourcenendpunkt, um den tatsächlichen API-Aufruf vorzunehmen.Öffnen Sie in Ihrem Code-Editor die Datei "API/index.js ", und fügen Sie dann den Code aus der Api/index.js-Datei ein.
Abrufen eines Zugriffstokens mithilfe von acquireTokenOnBehalfOf
In der Datei "API/index.js " erwirbt die Mid-Tier-App (EditProfileService-App) ein Zugriffstoken mithilfe der AcquireTokenOnBehalfOf-Funktion , die zum Aktualisieren des Profils im Namen dieses Benutzers verwendet wird.
async function getAccessToken(tokenRequest) {
try {
const response = await cca.acquireTokenOnBehalfOf(tokenRequest);
return response.accessToken;
} catch (error) {
console.error("Error acquiring token:", error);
throw error;
}
}
Der tokenRequest
Parameter wird wie im folgenden Code dargestellt definiert:
const tokenRequest = {
oboAssertion: req.headers.authorization.replace("Bearer ", ""),
authority: `https://${TENANT_SUBDOMAIN}.ciamlogin.com/${TENANT_ID}`,
scopes: ["User.ReadWrite"],
correlationId: `${uuidv4()}`,
};
In derselben Datei führt api/index.js die Mid-Tier-App (EditProfileService-App) einen Aufruf der Microsoft Graph-API durch, um das Profil des Benutzers zu aktualisieren:
let accessToken = await getAccessToken(tokenRequest);
fetch(GRAPH_ME_ENDPOINT, accessToken, "PATCH", req.body)
.then((response) => {
if (response.status === 204) {
res.status(response.status);
res.json({ message: "Success" });
} else {
res.status(502);
res.json({ message: "Failed, " + response.body });
}
})
.catch((error) => {
res.status(502);
res.json({ message: "Failed, " + error });
});
Testen Ihrer App
Führen Sie die folgenden Schritte aus, um Ihre App zu testen:
Um die Client-App auszuführen, bilden Sie das Terminalfenster, navigieren Sie in das App-Verzeichnis , und führen Sie dann den folgenden Befehl aus:
npm start
Um die Client-App auszuführen, bilden Sie das Terminalfenster, navigieren Sie zum API-Verzeichnis , und führen Sie dann den folgenden Befehl aus:
npm start
Öffnen Sie Ihren Browser, und navigieren Sie zu http://localhost:3000.. Wenn SSL-Zertifikatfehler auftreten, erstellen Sie eine
.env
-Datei, und fügen Sie die folgende Konfiguration hinzu:# Use this variable only in the development environment. # Remove the variable when you move the app to the production environment. NODE_TLS_REJECT_UNAUTHORIZED='0'
Wählen Sie die Schaltfläche Anmelden aus, und melden Sie sich an.
Geben Sie auf der Anmeldeseite Ihre E-Mail-Adresse ein, wählen Sie Weiter aus, geben Sie Ihr Kennwort ein und wählen Sie dann Anmelden aus. Wenn Sie kein Konto haben, wählen Sie den Link Kein Konto? Erstellen Sie eins aus, um den Registrierungsflow zu starten.
Um das Profil zu aktualisieren, wählen Sie den Link "Profilbearbeitung " aus. Die daraufhin angezeigte Seite sieht in etwa wie im folgenden Screenshot aus:
Um das Profil zu bearbeiten, wählen Sie die Schaltfläche "Profil bearbeiten" aus. Wenn Sie dies noch nicht getan haben, werden Sie von der App aufgefordert, eine MFA-Überprüfung durchzuführen.
Nehmen Sie Änderungen an den Profildetails vor, und wählen Sie dann die Schaltfläche "Speichern " aus.
Zugehöriger Inhalt
- Erfahren Sie mehr über die Microsoft Identity Platform und OAuth 2.0 On-Behalf-Of-Ablauf.