在 App Service 上部署后反应 msal-browser 不工作

React msal-browser not working after deploy on App Service

我使用“msal-browser”和“msal-react”创建了与 Azure AD B2C 集成的 React 应用程序。如果用户未登录,应用程序重定向到 AD 授权,如果用户登录,应用程序让用户使用整个应用程序。

一切都在当地运作良好。当我将应用程序部署到 Azure 应用程序服务时出现问题。

打开应用程序后,我正确地重定向到登录页面。登录后,我陷入了无限循环。 Url 从 https://domain.azurewebsites.net/ to https://domain.azurewebsites.net/#state=[...] and again to https://domain.azurewebsites.net/ and again to https://domain.azurewebsites.net/#state=[...] 等不断变化

在开发控制台中出现错误:POST

https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{signUpSignInPolicies}/oauth2/v2.0/token 400 (Bad Request)

这是我的代码: App.tsx:

function App() {
  return (
      <MainRoutes />
  );
}

export default withAuthHOC(App);

withAuthHOC.tsx:

const withAuthHOC = (WrappedComponent: React.FunctionComponent) => {
    return () => {
        const pca = new PublicClientApplication(msalConfig);
        useMsalRedirect();

        return (
            <MsalProvider instance={pca}>
                <AuthenticatedValidation />
                <AuthenticatedTemplate>
                    <WrappedComponent />
                </AuthenticatedTemplate>
            </MsalProvider>
        );
    }
};

export default withAuthHOC;

useMsalRedirect.tsx:

const useMsalRedirect = () => {
    const { instance } = useMsal();

    useEffect(() => {
        const callbackId = instance.addEventCallback((event: any) => {
            if (event.eventType === EventType.LOGIN_FAILURE) {
                if (event.error && event.error.errorMessage.indexOf("AADB2C90118") > -1) {
                    if (event.interactionType === InteractionType.Redirect) {
                        instance.loginRedirect(b2cPolicies.authorities.forgotPassword as RedirectRequest);
                    } else if (event.interactionType === InteractionType.Popup) {
                        instance.loginPopup(b2cPolicies.authorities.forgotPassword as RedirectRequest)
                            .catch(e => {
                                return;
                            });
                    }
                }
            }

            if (event.eventType === EventType.LOGIN_SUCCESS || event.eventType === EventType.ACQUIRE_TOKEN_SUCCESS) {
                if (event?.payload) {
                    if (event.payload.idTokenClaims["tfp"] === b2cPolicies.names.forgotPassword) {
                        window.alert("Password has been reset successfully. \nPlease sign-in with your new password.");
                        return instance.logout();
                    } else if (event.payload.idTokenClaims["tfp"] === b2cPolicies.names.editProfile) {
                        window.alert("Profile has been edited successfully. \nPlease sign-in again.");
                        return instance.logout();
                    }
                }
            }
        });

        return () => {
            if (callbackId) {
                instance.removeEventCallback(callbackId);
            }
        };
    }, [instance]);
}

export default useMsalRedirect;

AuthenticatedValidation.tsx:

export const AuthenticatedValidation = () => {
    const isAuthenticated = useIsAuthenticated();
    const { instance, inProgress } = useMsal();
    useEffect(() => {
        if (inProgress === InteractionStatus.None && !isAuthenticated) {
            instance.loginRedirect(loginRequest);
        }
    });

    return null;
}

export default AuthenticatedValidation;

authConfig.js

import { LogLevel } from "@azure/msal-browser";

export const b2cPolicies = {
    names: {
        signUpSignIn: "B2C_1A_signup_signin",
        forgotPassword: "B2C_1_passwordreset",
        editProfile: "B2C_1_profileediting"
    },
    authorities: {
        signUpSignIn: {
            authority: "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/B2C_1A_signup_signin",
        },
        forgotPassword: {
            authority: "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/B2C_1_passwordreset",
        },
        editProfile: {
            authority: "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/B2C_1_profileediting"
        }
    },
    authorityDomain: "{tenant}.b2clogin.com"
}

export const msalConfig = {
    auth: {
        clientId: "{clientId}",
        authority: b2cPolicies.authorities.signUpSignIn.authority,
        knownAuthorities: [b2cPolicies.authorityDomain],
        redirectUri: "https://domain.azurewebsites.net/", //localhost: "/"
        postLogoutRedirectUri: "https://domain.azurewebsites.net/", //localhost: "/"
        navigateToLoginRequestUrl: false,
    },
    cache: {
        cacheLocation: "sessionStorage",
        storeAuthStateInCookie: false,
    },
    system: {
        loggerOptions: {
            loggerCallback: (level, message, containsPii) => {
                if (containsPii) {
                    return;
                }
                switch (level) {
                    case LogLevel.Error:
                        console.error(message);
                        return;
                    case LogLevel.Info:
                        console.info(message);
                        return;
                    case LogLevel.Verbose:
                        console.debug(message);
                        return;
                    case LogLevel.Warning:
                        console.warn(message);
                        return;
                    default:
                        return;
                }
            }
        }
    }
};

export const loginRequest = {
    scopes: ['openid', 'profile'],
};

我使用 visual studio 代码部署应用程序。我的应用程序服务是带有启动命令的 Node 12 LTS:pm2 serve /home/site/wwwroot/build --no-daemon --spa

在 Azure AD B2C 属性中我有:

Inculde web app/web API: Yes
Allow implict flow: yes
Replay URLs and redirect URIs: https://domain.azurewebsites.net/ and https://localhost:3000
App ID URI: https://{tenant}.onmicrosoft.com/{clientId}
Include native client: yes

我的 signUpSignIn 策略是使用身份体验框架创建的。

该应用程序在本地主机上运行良好。将 export default with Auth HOC (App); 更改为 export default App; 后。该应用程序在 azure 上运行良好(禁用授权)。因此,我认为问题出在 authConfig.js 文件的配置上。有人知道我做错了什么吗?

我通过将实例化 PublicClientApplication 移动到反应组件之外解决了这个问题 - 索引 tsx