在当今的应用程序中,身份验证是强制性的,而微软的身份验证库(MSAL)是解决这一问题的有力方案。本文将向您展示在您自己的 React 代码中实现 MSAL 的所有细节。
在当今的数字环境中,确保用户数据的安全和隐私至关重要。无论您是在构建 Web 应用程序、移动应用程序还是其他任何需要用户身份验证的软件,Microsoft 的 React Authentication Library( MSAL-React
)都能提供一个强大的解决方案来简化这一过程。通过 MSAL-React,开发人员可以将安全身份验证无缝集成到他们的应用程序中,为用户提供安全、友好的使用体验。
在本综合指南中,我们将一步一步地指导您使用 MSAL-React 实施身份验证,帮助您利用微软身份验证平台的强大功能来保护用户数据并提高应用程序的可信度。无论您是经验丰富的开发人员还是刚刚开始工作,本文都将为您提供相关知识和工具,帮助您在 React 应用程序中采用强大的身份验证功能。
设置开发环境
构建应用程序所需的软件和工具有:
- Node.js 和 npm:从官方网站安装
Node.js
,其中包括npm
。npm
用于管理依赖关系和运行脚本。 - 复制模板: 该模板已构建了单页前端。下面是复制的方法:
- 首先,fork 仓库。
打开终端,在终端中运行此命令克隆版本库。
- 首先,fork 仓库。
git clone <your_repository_url>
在终端中使用此命令导航到项目目录。
cd msal-react-demo-template
导航到应用程序目录后,安装依赖项。
npm install
启动应用程序。
npm start
下面是该程序用户界面的初始外观。
- 安装必要的依赖项:在终端上使用以下命令安装 msal-react 和 msal-browser。
npm install --save @azure/msal-browser @azure/msal-react
项目结构如下:
msal-react-demo-template/ |-- node_modules/ |-- public/ |-- src/ | |-- components/ |-- NavBar.jsx |-- PageLayout.jsx |-- ProfileData.jsx |-- SignInButton.jsx |-- SignOutButton.jsx |-- WelcomeName.jsx | |-- pages/ |-- Home.jsx |-- Profile.jsx | |-- styles/ |-- theme.js | |-- App.js | |-- index.js |-- .gitignore |-- LICENSE |-- package-lock.json |-- package.json |-- README.md
Azure AD 应用程序注册
Azure Active Directory(Azure AD)是微软基于云的身份和访问管理服务。它提供了一个全面的解决方案,用于管理用户身份并确保对云中和企业内部应用程序和资源的访问安全。在本指南中,Azure AD 对于为应用程序添加身份验证和授权至关重要,可确保只有授权用户才能访问资源。
创建 Azure AD 应用程序注册并获取客户端 ID
- 访问 https://portal.azure.com/。
- 使用 Microsoft 帐户登录或创建一个帐户。
- 在搜索栏中搜索 “App Registration”。
- 点击 “New Registration”。
- 填写要用于应用程序的名称。
- 选择支持的帐户类型。本文仅使用 Microsoft 个人账户。
- 对于重定向 URI,选择 “Single-page application (SPA)”,并将 URI 设置为
http://localhost:3000/
。 - 点击 “Register”。
- 在 “Overview” 菜单上,可以复制客户端 ID。
MSAL-React 集成
在应用程序中配置 MSAL-React
,以启用安全且用户友好的基于 Azure AD 的身份验证和授权。
为 MSAL 设置配置
在 index.js
文件中,您将按照以下步骤配置将 MSAL-React
集成到 React 应用程序中。
- 导入必要的库:首先,从
msal-browser
中导入PublicClientApplication
。MSAL
(Microsoft Authentication Library,微软身份验证库)是一个便于 Azure AD 身份验证和授权的库。
import { PublicClientApplication } from '@azure/msal-browser';
- 实例化
pubClientApp
对象并提供配置选项:通过配置基本选项创建pubClientApp
对象。这些选项定义了应用程序与 Azure AD 的交互方式。下面是对每个选项的解释:
clientId
:这是从 Azure AD 应用程序注册中获得的应用程序客户端 ID。
权限authority
:授权 URL 指定了身份验证和授权的发生位置。对于 Azure AD 消费者账户,请使用 “https://login.microsoftonline.com/consumers”。redirectURI
:这是用户身份验证成功后将重定向到的 URI。应根据应用程序的设置进行配置。
const pubClientApp = new PublicClientApplication({ auth: { clientId: "Paste your client ID", authority: "https://login.microsoftonline.com/consumers", redirectUri: "/", }, });
注:为确保最佳性能,必须在组件树之外实例化 pubClientApp
对象。这样可以避免在组件重新渲染时重新创建该对象,从而降低效率。把它放在组件外,就能保证只创建一次,并在需要时重复使用。
- 将
pubClientApp
对象作为prop
传递给应用程序组件:现在,将pubClientApp
对象提供给应用程序组件。通常的做法是将其作为prop
传递给组件,这样应用程序就能无缝地管理身份验证和授权。
<App msalInstance={pubClientApp}/>
初始化 MSAL 提供程序
要使应用程序中的组件能够访问身份验证状态,应将它们封装在 MsalProvider
组件中。请按照以下步骤在 App.js
文件中进行设置:
- 首先,从
msal-react
库中导入MsalProvider
组件。
import { MsalProvider } from "@azure/msal-react";
- 用
MsalProvider
封装应用程序组件。提供msalInstance
属性并将配置好的应用程序实例传递给MsalProvider
。
function App({ msalInstance }) { return ( <MsalProvider instance={msalInstance}> <PageLayout> <Grid container justifyContent="center"> <Pages /> </Grid> </PageLayout> </MsalProvider> ); }
通过用 MsalProvider
封装组件,应用程序可以访问 msal-react
上下文。该上下文提供了对身份验证相关功能的访问,使在 React 应用程序中实施安全身份验证和授权变得更容易。
创建登录组件
要为应用程序创建登录组件,请按照 SignInButton.jsx
文件中的以下步骤操作:
- 首先导入
useMsal
钩子以访问MSAL
实例。
import { useMsal } from '@azure/msal-react';
- 利用
useMsal
钩子访问MSAL instance
。使用钩子创建名为instance
的变量,从而访问先前配置的MSAL instance
。
const { instance } = useMsal();
- 使用
instance.loginPopup()
方法定义 “handleLogin” 函数。该函数通过弹出窗口提示用户使用用户名和密码登录
const handleLogin = () => { instance.loginPopup(); };
- 在用户首次登录时,通过指定
scopes
等选项来请求权限,从而定制登录体验。
const handleLogin = () => { instance.loginPopup({ scopes: ["user.read"], }); };
- 为组件中的按钮添加调用
handleLogin
函数的onClick
属性。
<Button color="inherit" onClick={handleLogin}> Sign in </Button>
以下是 SignInButton.jsx
文件,供参考:
import Button from "@mui/material/Button"; // Importing a button component from the Material-UI library. import { useMsal } from "@azure/msal-react"; // Importing the useMsal hook from Azure MSAL for handling authentication. export const SignInButton = () => { const { instance } = useMsal(); // Access the instance object from the useMsal hook. const handleLogin = () => { instance.loginPopup({ scopes: ["user.read"], // Configuring the loginPopup with the "user.read" scope. }); }; return ( <Button color="inherit" onClick={handleLogin}> Sign in {/* Render a button with the label "Sign in" and bind the handleLogin function to the click event. */} </Button> ); };
创建签出组件
创建签出组件的方法与创建签入组件类似。请在 SignOutButton.jsx
文件中按照以下步骤创建签出组件:
- 从
msal-react
中导入useMsal
钩子,以访问用于处理签出的MSAL instance
。
import { useMsal } from '@azure/msal-react';
- 利用
useMsal
钩子访问MSAL instance
。使用useMsal
钩子创建一个名为instance
的变量。这样就可以访问为应用程序配置的MSAL instance
。
const { instance } = useMsal();
- 定义
handleLogout
函数,该函数使用instance.logoutPopup()
方法。该函数会触发一个用于注销用户的弹出窗口,并在注销后将用户重定向到主页。
const handleLogout = () => { instance.logoutPopup(); };
- 将
handleLogout
功能整合到组件中按钮的onClick
属性中。
<Button color="inherit" onClick={handleLogout}> Sign out </Button>;
下面是 SignOutButton.jsx
文件,供参考:
import Button from "@mui/material/Button"; // Importing a button component from the Material-UI library. import { useMsal } from "@azure/msal-react"; // Importing the useMsal hook from Azure MSAL for handling authentication. export const SignOutButton = () => { const { instance } = useMsal(); // Access the instance object from the useMsal hook. const handleLogout = () => { instance.logoutPopup(); // Call the logoutPopup method from the instance object to initiate the sign-out process. }; return ( <Button color="inherit" onClick={handleLogout}> Sign out {/* Render a button with the label "Sign out" and bind the handleLogout function to the click event. */} </Button> ); };
根据身份验证状态有条件地渲染 UI 元素
要根据用户的身份验证状态有条件地在应用程序中呈现 UI 元素,请在 NavBar.jsx
和 Home.jsx
文件中按照以下步骤操作。
- 在
NavBar.jsx
文件中
从 msal-react
导入 useIsAuthenticated
钩子。此钩子允许根据用户的身份验证状态有条件地呈现元素。
import { useIsAuthenticated } from "@azure/msal-react";
根据用户的身份验证状态,有条件地在组件中呈现 WelcomeName
元素。
// Conditional rendering: Display the WelcomeName component only if isAuthenticated is true. { isAuthenticated ? <WelcomeName /> : null; }
根据用户的身份验证状态有条件地渲染 SignInButton
和 SignOutButton
元素。如果已通过身份验证,则渲染 SignOutButton
,如果未通过身份验证,则渲染 SignInButton
。
// Display the SignOutButton if isAuthenticated is true, otherwise display the SignInButton. { isAuthenticated ? <SignOutButton /> : <SignInButton />; }
- 在
Home.jsx
文件中:
利用 msal-react
提供的 AuthenticatedTemplate
和 UnauthenticatedTemplate
组件实现条件文本呈现。从 msal-react
导入 AuthenticatedTemplate
和 UnauthenticatedTemplate
。
import { AuthenticatedTemplate, UnauthenticatedTemplate } from "@azure/msal-react"
在 AuthenticatedTemplate
中包围包含文本的 Typography
元素,这些文本将在用户登录时可见。
<AuthenticatedTemplate> <Typography variant="h6"> You are signed-in. Select profile to call Microsoft Graph. </Typography> </AuthenticatedTemplate>;
在 UnauthenticatedTemplate
中封装用户签出时应可见的 Typography
元素。
<UnauthenticatedTemplate> <Typography variant="h6"> Please sign in to see your profile information. </Typography> </UnauthenticatedTemplate>;
下面是这款应用程序的预览,它可以根据你的登录状态有选择性地显示特定信息。
使用 Tokens
我们将深入探讨获取访问 tokens 和发出经过验证的 API 请求的实际步骤。访问 tokens 是安全访问外部资源的关键,我们将探讨如何在应用程序中有效使用它们。
获取访问 tokens
要获取访问 tokens 以发出经过验证的 API 请求,请按照 Profile.jsx
文件中的以下步骤操作:
- 在
Profile.jsx
文件开头导入必要的依赖项。这些依赖项是处理身份验证和获取访问 tokens 所必需的。
import { useMsalAuthentication } from "@azure/msal-react"; import { InteractionType } from "@azure/msal-browser"; import { useEffect, useState } from "react";
- 使用
useState
钩子创建名为displayData
的状态变量。该状态变量将存储从已验证的应用程序接口获取的数据
const [displayData, setDisplayData] = useState(null);
- 利用
useMsalAuthentication
钩子获取访问 tokens。该钩子需要两个参数:interaction type
和指定请求scopes
的对象。
const { result, error } = useMsalAuthentication(InteractionType.Redirect, { scopes: ["user.read"], });
要处理访问 token 并执行相关操作,请使用 useEffect
钩子。当组件挂载时,应运行此效果。在此效果中,您可以运行一系列检查:
- 检查
displayData
是否存在,以防止在数据已经可用的情况下不必要地重新执行效果。 - 检查是否存在任何身份验证错误,并将其记录到控制台以进行错误处理。
- 检查
result
是否存在,然后提取访问 token。
useEffect(() => { if (!displayData) { return; } if (error) { console.log(error); return; } if (result) { const accessToken = result.accessToken; } }, [displayData, error, result]);
执行通过身份验证的 API 请求
要在 React 应用程序中发出通过身份验证的 API 请求并处理响应,请按照以下步骤操作:
在 src 文件夹中创建名为 Fetch.js
的新文件,以封装用于发出 API 请求的函数。
- 在
Fetch.js
文件中:
定义一个名为 retrieveData
的函数,将 endpoint
和 access token
作为参数。该函数将处理 API 请求。
export const retrieveData = (endpoint, accessToken) => {};
在 retrieveData
函数中,创建 Headers
对象,并用访问 token(bearer
token)设置授权标题。
const headers = new Headers(); const bearer = `Bearer ${accessToken}`; headers.append("Authorization", bearer);
创建一个包含 HTTP method
和 headers
的 options
对象。
const options = { method: "GET", headers: headers, };
使用 fetch
函数发出 API 请求。使用 .then()
处理响应,并使用 .catch()
捕捉任何错误。
return fetch(endpoint, options) .then((response) => response.json()) .catch((error) => console.log(error));
下面是 Fetch.js
文件,供参考:
export const retrieveData = (endpoint, accessToken) => { const headers = new Headers(); const bearer = `Bearer ${accessToken}`; headers.append("Authorization", bearer); const options = { method: "GET", headers: headers, }; return fetch(endpoint, options) .then((response) => response.json()) .catch((error) => console.log(error)); };
- 在
Profile.jsx
中:
从 Fetch.js
导入 retrieveData
函数。这将为您的配置文件组件做好准备,以便利用该功能发出经过身份验证的 API 请求。
import { retrieveData } from "../Fetch";
使用 retrieveData
方法发出经过验证的 API 请求。例如,可以将 endpoint
设置为 “https://graph.microsoft.com/v1.0/me”。
if (result) { const accessToken = result.accessToken; retrieveData("https://graph.microsoft.com/v1.0/me", accessToken) .then((response) => setDisplayData(response)) .catch((error) => console.log(error)); }
在组件的 return
语句中,如果存在数据,则渲染数据( displayData
);否则,不显示任何数据。
return <>{displayData ? <ProfileData displayData={displayData} /> : null}</>;
下面是 Profile.jsx
文件,供参考:
import { ProfileData } from "../components/ProfileData"; // Importing the ProfileData component import { useMsalAuthentication } from "@azure/msal-react"; // Importing the useMsalAuthentication hook from Azure MSAL import { InteractionType } from "@azure/msal-browser"; // Importing the InteractionType from Azure MSAL import { useEffect, useState } from "react"; // Importing the useEffect and useState hooks from React import { retrieveData } from "../Fetch"; // Importing the retrieveData function from a custom module export const Profile = () => { const [displayData, setDisplayData] = useState(null); // Initializing a state variable displayData using useState const { result, error } = useMsalAuthentication(InteractionType.Redirect, { scopes: ["user.read"], // Configuring the useMsalAuthentication hook with a specified scope }); useEffect(() => { if (!displayData) { return; // If displayData is already populated, do nothing } if (error) { console.log(error); // If there's an error, log it to the console return; } if (result) { const accessToken = result.accessToken; // Access the accessToken property from the result object retrieveData("https://graph.microsoft.com/v1.0/me", accessToken) // Call the retrieveData function with the access token .then((response) => setDisplayData(response)) // Set the displayData state with the response data .catch((error) => console.log(error)); // Handle and log any errors } }, [displayData, error, result]); // Run this effect when displayData, error, or result changes return <>{displayData ? <ProfileData displayData={displayData} /> : null}</>; // Conditional rendering of the ProfileData component based on the displayData state };
下面是该应用的预览版,展示了用户登录时的具体细节。
显示已登录用户的名称
要在用户界面中显示已登录用户的姓名以增强用户体验,请按以下步骤操作:
- 在
index.js
文件:
导入必要的依赖项并设置 MSAL
事件回调以处理成功登录事件。
import { PublicClientApplication, EventType } from "@azure/msal-browser"; // Add an MSAL event callback to set the active account pubClientApp.addEventCallback((event) => { if (event.eventType === EventType.LOGIN_SUCCESS) { console.log(event); pubClientApp.setActiveAccount(event.payload.account); } });
- 在
WelcomeName.jsx
组件中:
导入访问应用程序实例和管理组件状态所需的依赖项。
import { useMsal } from "@azure/msal-react"; import { useState, useEffect } from "react";
定义状态变量 username
,用于存储登录用户的用户名。
const [username, setUsername] = useState('');
使用 useMsal
钩子访问之前创建的应用程序实例( instance
)。
const { instance } = useMsal();
在 useEffect
钩子中,将 currentAccount
设置为活动账户,并更新 username
状态变量。确保在依赖关系数组中包含 instance
,以观察变化。
useEffect(() => { const currentAccount = instance.getActiveAccount(); if (currentAccount) { setUsername(currentAccount.username); } }, [instance]);
在组件的 return
语句中,使用 Typography
组件在用户界面中显示用户名。
return <Typography variant="h6">Welcome, {username}</Typography>;
登录时显示用户名的应用程序快照:
错误处理
要在应用程序中使用 MSAL 启用错误处理和日志记录功能,请按照以下步骤操作:
打开 index.js
文件:
- 在
pubClientApp
对象中,包含一个cache
对象,其中包含cacheLocation
和storeAuthStateInCookie
等选项。这些选项有助于控制验证工件的缓存和管理方式。
cache: { cacheLocation: 'localStorage', storeAuthStateInCookie: false, }
- 在
pubClientApp
对象中包含一个system
对象,并为日志配置定义loggerOptions
。这样就可以指定MSAL
处理日志的方式。
system: { loggerOptions: { loggerCallback: (level, message, containsPII) => { console.log(message); // Define a callback function to handle log messages (in this case, logging to the console). }, logLevel: 'Verbose' // Set the log level to 'Verbose' (providing detailed logs including debug information). } }
有了这些配置, MSAL
就会在控制台中记录交互、错误和其他信息。您可以使用这些信息来调试和监控身份验证过程。
请注意,此设置可帮助您调试和监控与身份验证相关的活动,并排除用户与 Azure AD 交互过程中可能出现的任何问题。
记录交互的浏览器控制台预览。
处理身份验证错误
要在 MSAL 应用程序中处理身份验证错误和索赔挑战,请按照以下步骤操作:
- 在
index.js
文件中
在 auth
对象中添加 clientCapabilities
选项。该选项声明应用程序能够处理索赔挑战。
auth: { clientId: "5d804fed-8b0e-4c9b-b949-6020d4945ead", authority: "https://login.microsoftonline.com/consumers", redirectUri: "http://localhost:3000/", clientCapabilities: ['CP1'] },
- 在
Fetch.js
文件中:添加一个名为handleClaims
的函数,用于检查响应的状态代码。- 如果状态为 200(表示成功),则返回 JSON 格式的响应。
如果状态为 401,它会检查响应头是否包含 “authenticated”。如果包含,则会从标头中提取 claimsChallenge 并将其存储到 sessionStorage 中。
- 如果状态为 200(表示成功),则返回 JSON 格式的响应。
const handleClaims = (response) => { if (response.status === 200) { return response.json(); // If the response status is 200 (OK), parse it as JSON and return the result. } else if (response.status === 401) { if (response.headers.get("www-authenticate")) { const authenticateHeader = response.headers.get("www-authenticate"); const claimsChallenge = authenticateHeader .split(" ") .find((entry) => entry.includes("claims=")) // Find the entry in the authenticateHeader that contains "claims=". .split('claims="')[1] // Extract the part of the entry after 'claims="'. .split('",')[0]; // Extract the part before the next '"'. sessionStorage.setItem("claimsChallenge", claimsChallenge); // Store the claims challenge in session storage. return; // Return without further processing. } throw new Error(`Error $(response.status)`); // If there's no 'www-authenticate' header, throw an error. } else { throw new Error(`Error $(response.status)`); // If the response status is neither 200 nor 401, throw an error. } };
修改 fetch
调用,通过 handleClaims
函数传递 response
。这可确保对响应进行处理,以处理索赔质疑或其他错误。
return fetch(endpoint, options) .then((response) => handleClaims(response)) .catch((error) => console.log(error));
- 在
Profile.jsx
组件中:
在 useMsalAuthentication
配置中添加一个参数 claims
。该参数设置为存储在 sessionStorage
中的 claimsChallenge
。
const { result, error } = useMsalAuthentication(InteractionType.Redirect, { scopes: ["user.read"], claims: sessionStorage.getItem("claimsChallenge") ? window.atob(sessionStorage.getItem("claimsChallenge")) : undefined, });
通过这些步骤,您可以在 MSAL
应用程序中处理身份验证错误和理赔挑战,使其更加强大,并能够在身份验证过程中管理自定义理赔挑战。
这有一份关于解决 Microsoft Entra ID 问题的故障排除指南。
小结
本综合指南提供了使用 MSAL-React
实施身份验证的分步指南。它帮助读者建立开发环境、配置 MSAL-React
、创建签入和签出组件、提出经过验证的 API 请求,以及有效处理身份验证错误。
评论留言