如果令牌已过期,如何使用“React AZURE MSAL SSO”将用户重定向到登录页面?

问题描述 投票:0回答:1

功能:ReactJS MSAL SSO 登录、注销、刷新令牌并在令牌过期后重定向到登录页面。

问题:如果令牌已过期,则无法重定向到登录(使用 ReactJS 的 MSAL SSO)。

参考此链接 - 如何在 azure msal 反应中处理令牌过期?

下面的代码非常适合登录、注销、令牌刷新。但是,如果令牌已过期,则无法重定向登录:-

App.js:-

import { MsalProvider } from "@azure/msal-react";
import MainContent from "./views/MainContent";
import "./App.css";

const App = ({ instance }) => {
  return (
    <MsalProvider instance={instance}>
      <MainContent></MainContent>
    </MsalProvider>
  );
};

export default App;

MainContent.js:-

import React, { useEffect } from "react";
import {
  AuthenticatedTemplate,
  useMsal,
  UnauthenticatedTemplate,
} from "@azure/msal-react";
import { useShallow } from "zustand/react/shallow";
import useAuthStore from "../store/authStore";
import { jwtDecode } from "jwt-decode";
import AppRoutes from "../routes/AppRoutes";
import checkUserPermissions from "../utils/checkUserPermissions";
import AutoSignIn from "./AutoSignIn";
import { InteractionRequiredAuthError } from "@azure/msal-browser";

const MainContent = () => {
  const { instance } = useMsal();
  const activeAccount = instance.getActiveAccount();
  const REFRESH_THRESHOLD = 600; // 10 mins (60 seconds * 10 mins = 600)

  const { setLoginState } = useAuthStore(
    useShallow((state) => ({
      setLoginState: state.setLoginState,
    }))
  );

  const { isLoggedOut } = useAuthStore(
    useShallow((state) => ({
      isLoggedOut: state.isLoggedOut,
    }))
  );

  const saveActiveToken = (token) => {
    if (token) {
      sessionStorage.setItem("access-token", token);
    }
  };

  if (activeAccount?.idToken && typeof activeAccount?.idToken != "undefined") {
    saveActiveToken(activeAccount?.idToken);
  }

  const handleLogoutRedirect = () => {
    instance
      .logoutRedirect()
      .catch((error) => console.log("logout error: ", error));

      console.log(instance.getAllAccounts());
      debugger
    };

  const refreshToken = async () => {
    await instance.acquireTokenSilent(activeAccount).catch(async (error) => {
      if (error instanceof InteractionRequiredAuthError) {
        await instance.acquireTokenRedirect(activeAccount);
      }
    });
    saveActiveToken(activeAccount?.idToken);
  };

  useEffect(() => {
    if (isLoggedOut) handleLogoutRedirect();
  }, [isLoggedOut]);

  useEffect(() => {
    setInterval(() => {
      try {
        const token = sessionStorage.getItem("access-token");
        if (typeof token != "undefined" && token != "") {
          const decodedToken = jwtDecode(token);
          const currentTime = Math.floor(Date.now() / 1000); // Current time in seconds
          const timeUntilExpiry = decodedToken.exp - currentTime;
          if (timeUntilExpiry <= REFRESH_THRESHOLD) {
            refreshToken();
          }
        }
      } catch (err) {
        console.log("Printing setInterval() Error: ", err);
      }
    }, 60000);
  }, []);

  return (
    <div>
      <AuthenticatedTemplate>
        {activeAccount ? <AppRoutes /> : null}
      </AuthenticatedTemplate>
      <UnauthenticatedTemplate>
        <AutoSignIn instance={instance} />
      </UnauthenticatedTemplate>
    </div>
  );
};

export default MainContent;
reactjs azure-ad-msal msal.js msal-react
1个回答
0
投票

https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/token-lifetimes.md#avoiding-interactive-interruptions-in-the-用户会话中间

var request = {
    scopes: ["Mail.Read"],
    account: currentAccount,
    forceRefresh: true
    refreshTokenExpirationOffsetSeconds: 7200 // 2 hours * 60 minutes * 60 seconds = 7200 seconds
};

const tokenResponse = await msalInstance.acquireTokenSilent(request).catch(async (error) => {
    if (error instanceof InteractionRequiredAuthError) {
        // fallback to interaction when silent call fails
        await msalInstance.acquireTokenRedirect(request);
    }
});

将此函数添加到useEffect中并更新组件

import React, { useEffect } from "react";
import { useMsal } from "@azure/msal-react";
import { InteractionRequiredAuthError } from "@azure/msal-browser";

const YourComponent = () => {
  const { instance, accounts } = useMsal();

  useEffect(() => {
    const checkTokenExpiration = async () => {
      if (accounts.length > 0) {
        const currentAccount = accounts[0];
        const request = {
          scopes: ["Mail.Read"],
          account: currentAccount,
          forceRefresh: true, // Forces to refresh token
          refreshTokenExpirationOffsetSeconds: 7200, // 2 hours
        };

        try {
          // Try to acquire a token silently
          const tokenResponse = await instance.acquireTokenSilent(request);
          console.log("Token acquired:", tokenResponse);
        } catch (error) {
          if (error instanceof InteractionRequiredAuthError) {
            // Fallback to interactive token acquisition when silent call fails
            await instance.acquireTokenRedirect(request);
          } else {
            console.error("Error acquiring token silently:", error);
          }
        }
      }
    };

    checkTokenExpiration();
  }, [accounts, instance]);

  return <div>{/* Your component content */}</div>;
};

export default YourComponent;
© www.soinside.com 2019 - 2024. All rights reserved.