我们决定希望使用 JWT 机制来保护我们的端点之一。 身份验证是通过 Microsoft Identity Platform 使用 Microsoft Entra ID 完成的。 (这是我第一次集成这样的系统,并且之前没有关于 JWT 的一般经验,特别是整个 MS Azure 身份验证世界。)
现在,我已成功将 MSAL 集成到我的前端中,并完成了测试用户的登录过程,并且被正确重定向到我开始登录旅程的位置。 但是我在
localStorage
中找不到获取的Entra ID令牌(根据我的msalConfig
应该在哪里)。
我怀疑这是因为令牌存储在不同的域下,因此我无法读取它。 但我需要阅读它,以便我可以将其作为不记名令牌按预期发送到端点。
是的,我阅读了文档(但不是全部),但对所有新术语感到非常头晕。那么这可能与文档中不断出现的
audience
有关吗?
在claims
、scopes
、audience
、authority
、tenants
、clientId
等之间。我必须承认我有点迷失。
这是我的
msalConfig
和我的loginRequest
export const msalConfig = {
auth: {
clientId: globals.meta.config.MSAL_CLIENT_ID,
authority: 'https://galactus.some-example-authority.com/',
redirectUri: 'https://example.org/pages/galactus-login',
postLogoutRedirectUri: '/',
navigateToLoginRequestUrl: false,
},
cache: {
cacheLocation: 'localStorage',
storeAuthStateInCookie: false,
},
}
export const loginRequest = {
scopes: [],
}
最初,我注册了一个应用程序,其中
API permissions
:
在“身份验证”选项卡中,我在“单页应用程序”平台中将重定向 URI 添加为 http://localhost:3000:
启用
public-client流选项,如下所示:
在我的例子中,我使用了下面的代码文件,并通过成功调用 MS Graph API 获得了带有登录用户详细信息的令牌,如下所示:
authConfig.js:
// src/authConfig.js
export const msalConfig = {
auth: {
clientId: "appId",
authority: "https://login.microsoftonline.com/tenantId",
redirectUri: "http://localhost:3000", // Redirect URI registered in Azure AD
},
cache: {
cacheLocation: "localStorage",
storeAuthStateInCookie: false,
},
};
export const loginRequest = {
scopes: ["User.Read", "openid"], // Scopes for MS Graph API or custom API
};
// src/App.js
import React, { useEffect, useState } from "react";
import { msalConfig, loginRequest } from "./authConfig";
import { PublicClientApplication } from "@azure/msal-browser";
import axios from "axios";
const msalInstance = new PublicClientApplication(msalConfig);
const App = () => {
const [accessToken, setAccessToken] = useState("");
const [idToken, setIdToken] = useState("");
const [userProfile, setUserProfile] = useState(null);
const [userName, setUserName] = useState("");
// Initialize MSAL on app load
useEffect(() => {
const initializeMSAL = async () => {
try {
await msalInstance.initialize();
console.log("MSAL initialized successfully");
} catch (error) {
console.error("MSAL initialization failed: ", error);
}
};
initializeMSAL();
}, []);
const loginAndGetToken = async () => {
try {
const loginResponse = await msalInstance.loginPopup(loginRequest);
console.log("Login successful!", loginResponse);
// Set the active account after successful login
msalInstance.setActiveAccount(loginResponse.account);
// Access tokens and ID token
const newAccessToken = loginResponse.accessToken;
const newIdToken = loginResponse.idToken; // Get the ID token
setAccessToken(newAccessToken);
setIdToken(newIdToken);
setUserName(loginResponse.account.name);
// Call the Graph API to fetch user profile info
await callGraphAPI(newAccessToken);
} catch (error) {
console.error("Login failed: ", error);
alert(`Login failed: ${error.message}`);
}
};
const callGraphAPI = async (token) => {
try {
const response = await axios.get("https://graph.microsoft.com/v1.0/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});
console.log("Graph API Response:", response.data);
setUserProfile(response.data);
} catch (error) {
console.error("Graph API call failed:", error);
}
};
const logout = () => {
msalInstance.logoutPopup();
};
return (
<div>
<h1>MSAL Login</h1>
{!accessToken ? (
<button onClick={loginAndGetToken}>Login</button>
) : (
<div>
<h2>Logged in as: {userName}</h2> {/* Display user's name */}
<button onClick={logout}>Logout</button>
</div>
)}
{accessToken && (
<div>
<h2>Access Token:</h2>
<p>{accessToken}</p>
</div>
)}
{idToken && (
<div>
<h2>ID Token:</h2>
<p>{idToken}</p>
</div>
)}
{userProfile && (
<div>
<h2>User Profile:</h2>
<p><strong>Name:</strong> {userProfile.displayName}</p>
<p><strong>Email:</strong> {userProfile.mail || userProfile.userPrincipalName}</p>
<p><strong>Job Title:</strong> {userProfile.jobTitle}</p>
</div>
)}
</div>
);
};
export default App;
jwt.ms
网站来解码它,并检查 aud
、
scp
等声明来验证它:如果您公开了任何具有自定义范围的 API,请确保在获取令牌时使用
scopes 参数值作为 api://appId/scopename
。