我正在我的应用程序中使用react-msal。我需要获取访问令牌并将其全局附加到 axios,但不幸的是,他们只提供挂钩来获取访问令牌(据我所知)。
到目前为止,这是我的 api.js 文件。
import axios from "axios";
import { useMsal } from "@azure/msal-react";
const axiosInstance = axios.create({
baseURL: "https://localhost:4211/api",
});
const { instance, accounts } = useMsal();
instance
.acquireTokenSilent({
...loginApiRequest,
account: accounts[0],
})
.then((response) => {
axiosInstance.defaults.headers.common[
"Authorization"
] = `Bearer ${response.accessToken}`;
})
.catch((error) => {
console("Error acquiring access token");
});
export default axiosInstance;
这是我在组件中调用 API。
api.get('/foods').then(response => {
alert(response.data)
}).catch(error => {
console.log(error.response)
})
但是我遇到了一个问题:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component.
,这很明显,但我需要替代方案来获取访问令牌并将其作为标头的一部分全局分配给我的 axios,这样我就不需要每次都重写标头需要调用端点。
您可以使用传递到
PublicClientApplication
中的 MsalProvider
实例。
要获取账户请致电
instance.getAllAccounts()
。
您无法在组件或上下文之外访问
inProgress
值,但由于您只是使用 acquireTokenSilent 您可能不需要它。
下面是我的工作示例。
import axios from 'axios';
import * as App from '../index'
import * as utils from './utils'
const instance = axios.create({
baseURL: utils.getEndpoint(),
timeout: 15000
});
instance.interceptors.request.use(function (config) {
const instance = App.msalInstance;
const accounts = instance.getAllAccounts();
const accessTokenRequest = {
scopes: ["user.read"],
account: accounts[0],
};
return instance
.acquireTokenSilent(accessTokenRequest)
.then((accessTokenResponse) => {
// Acquire token silent success
let accessToken = accessTokenResponse.accessToken;
// Call your API with token
config.headers.Authorization = `Bearer ${accessToken}`;
return Promise.resolve(config)
})
}, function (error) {
return Promise.reject(error);
});
instance.interceptors.response.use((response) => {
if(response.status === 401) {
// Clear local storage, redirect back to login
window.location.href = "/logout"
}
return response;
}, (error) => {
return Promise.reject(error);
});
export default instance
和下面的index.js
import React from "react";
import ReactDOM from "react-dom";
import { PublicClientApplication, EventType } from "@azure/msal-browser";
import { msalConfig } from "./authConfig";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
export const msalInstance = new PublicClientApplication(msalConfig());
// Default to using the first account if no account is active on page load
if (!msalInstance.getActiveAccount() && msalInstance.getAllAccounts().length > 0) {
// Account selection logic is app dependent. Adjust as needed for different use cases.
msalInstance.setActiveAccount(msalInstance.getAllAccounts()[0]);
}
// Optional - This will update account state if a user signs in from another tab or window
msalInstance.enableAccountStorageEvents();
msalInstance.addEventCallback((event) => {
if (event.eventType === EventType.LOGIN_SUCCESS && event.payload.account) {
const account = event.payload.account;
msalInstance.setActiveAccount(account);
}
});
ReactDOM.render(<App pca={msalInstance} />,
document.getElementById("app"),
);
serviceWorker.unregister();
对于未来的读者来说,拉维的解决方案是有效的。 仅替换
export const msalInstance = new PublicClientApplication(msalConfig());
与 export const msalInstance = new PublicClientApplication(msalConfig);
这是一个 React 应用程序,对吧?
您不能从 React 组件外部调用钩子,或其他钩子。
https://reactjs.org/docs/hooks-rules.html
你可以这样做:
const App = () => {
const { instance, accounts } = useMsal();
useEffect(() => {
instance.acquireTokenSilent()
.then(() => {})
.catch(() => {})
},[]);
};