BrowserAuthError:interaction_in_progress:当前正在进行与 azure/msal-browser@2.11.2 的交互

bee*_*est 4 reactjs azure-active-directory azure-ad-msal

尝试使用@azure/msal-react@1.0.0-alpha.6 和@azure/msal-browser@2.11.2 在 React 应用程序中登录重定向时出现此错误。登录数据正确返回,但在控制台中引发异常。

未捕获(承诺)BrowserAuthError:interaction_in_progress:交互正在进行中。请确保在调用交互式 API 之前已完成此交互。

import * as msal from "@azure/msal-browser";

const msalConfig = {
  auth: {
      clientId: '995e81d0-',
      authority: 'https://login.microsoftonline.com/3a0cf09b-',
      redirectUri: 'http://localhost:3000/callback'
  },
  cache: {
    cacheLocation: "sessionStorage", // This configures where your cache will be stored
    storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
  }
};
const msalInstance = new msal.PublicClientApplication(msalConfig);
try {
  msalInstance.handleRedirectPromise()
    .then(res=>{
      console.log(res)
    })
    .catch(err => {
      console.error(err);
    });

  var loginRequest = {
    scopes: ["api://58ca819e-/access_as_user"] // optional Array<string>
  };
  msalInstance.loginRedirect(loginRequest);
} catch (err) {
  // handle error
  console.log(err)
}
Run Code Online (Sandbox Code Playgroud)

例外

Uncaught (in promise) BrowserAuthError: interaction_in_progress: Interaction is currently in progress. Please ensure that this interaction has been completed before calling an interactive API.
    at BrowserAuthError.AuthError [as constructor] (http://localhost:3000/static/js/vendors~main.chunk.js:852:20)
    at new BrowserAuthError (http://localhost:3000/static/js/vendors~main.chunk.js:8943:24)
    at Function.BrowserAuthError.createInteractionInProgressError (http://localhost:3000/static/js/vendors~main.chunk.js:9023:12)
    at PublicClientApplication.ClientApplication.preflightInteractiveRequest (http://localhost:3000/static/js/vendors~main.chunk.js:13430:30)
    at PublicClientApplication.<anonymous> (http://localhost:3000/static/js/vendors~main.chunk.js:12581:33)
    at step (http://localhost:3000/static/js/vendors~main.chunk.js:215:17)
    at Object.next (http://localhost:3000/static/js/vendors~main.chunk.js:146:14)
    at http://localhost:3000/static/js/vendors~main.chunk.js:118:67
    at new Promise (<anonymous>)
    at __awaiter (http://localhost:3000/static/js/vendors~main.chunk.js:97:10)
    at PublicClientApplication.ClientApplication.acquireTokenRedirect (http://localhost:3000/static/js/vendors~main.chunk.js:12565:12)
    at PublicClientApplication.<anonymous> (http://localhost:3000/static/js/vendors~main.chunk.js:13760:16)
    at step (http://localhost:3000/static/js/vendors~main.chunk.js:215:17)
    at Object.next (http://localhost:3000/static/js/vendors~main.chunk.js:146:14)
    at http://localhost:3000/static/js/vendors~main.chunk.js:118:67
    at new Promise (<anonymous>)
    at __awaiter (http://localhost:3000/static/js/vendors~main.chunk.js:97:10)
    at PublicClientApplication.loginRedirect (http://localhost:3000/static/js/vendors~main.chunk.js:13755:12)
    at Module.<anonymous> (http://localhost:3000/static/js/main.chunk.js:192:16)
    at Module../src/App.tsx (http://localhost:3000/static/js/main.chunk.js:292:30)
    at __webpack_require__ (http://localhost:3000/static/js/bundle.js:857:31)
    at fn (http://localhost:3000/static/js/bundle.js:151:20)
    at Module.<anonymous> (http://localhost:3000/static/js/main.chunk.js:2925:62)
    at Module../src/index.tsx (http://localhost:3000/static/js/main.chunk.js:3028:30)
    at __webpack_require__ (http://localhost:3000/static/js/bundle.js:857:31)
    at fn (http://localhost:3000/static/js/bundle.js:151:20)
    at Object.1 (http://localhost:3000/static/js/main.chunk.js:3570:18)
    at __webpack_require__ (http://localhost:3000/static/js/bundle.js:857:31)
    at checkDeferredModules (http://localhost:3000/static/js/bundle.js:46:23)
    at Array.webpackJsonpCallback [as push] (http://localhost:3000/static/js/bundle.js:33:19)
    at http://localhost:3000/static/js/main.chunk.js:1:67
Run Code Online (Sandbox Code Playgroud)

dap*_*pug 25

我相信这是正确的答案和设置方法。这里的其他人引导我找到解决这个问题的线索。

太长了;像这样设置你的代码:

// authRedir.ts  (or authRedir.vue inside mounted())
await msalInstance.handleRedirectPromise();

Run Code Online (Sandbox Code Playgroud)
// mySignInPage.ts (or userprofile.vue, or whatever page invokes a sign-in)
await msalInstance.handleRedirectPromise();

async signIn(){
  const loginRequest: msal.RedirectRequest = {
    scopes: ["openid", "profile", "offline_access","your_other_scopes"]
    redirectUri: "http://localhost:8080/authredirect"
        };

  const accounts = msalInstance.getAllAccounts();
  if (accounts.length === 0) {

    await msalInstance.loginRedirect();
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您正确执行此操作,则不需要共享代码@shevchenko-vladislav,其中setActiveAccount()必须由您手动完成。请记住,无论您在应用程序中调用此方法,都要验证所有异步/等待!handleRedirectPromise().then()请注意我在我的主文件中实际上没有使用任何东西authredirect.vue。刚刚handleRedirectPromise()加载。

Stackoverflow 上的其他解决方案建议执行诸如检查和删除会话中的交互状态之类的操作。不!如果登录后仍保留该状态,则意味着该过程未正确完成!MSAL 会自行清理!

完整详细信息:

了解 MSAL 在整个生命周期中实际执行的操作(尤其是与弹出窗口相对的 redir 路径)非常重要,遗憾的是文档未能做好工作。我发现这个小“旁注”非常非常重要:

https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/errors.md#interaction_in_progress

“如果您正在调用loginRedirectacquireTokenRedirect来自不属于您的页面,redirectUri则需要确保 handleRedirectPromise在redirectUri页面以及您发起重定向的页面上调用并等待。这是因为redirectUri页面将发起重定向回来到最初调用的页面loginRedirect,该页面将处理令牌响应。”

换句话说,您的重定向页面和调用登录请求的页面都必须handleRedirectPromise()页面加载时调用(或者在我的情况下调用 Mounted() ,因为我使用的是 Vue)

就我而言,我有这个:

  • http://localhost:8080/authredirect *
  • http://localhost:8080/用户配置文件

*只有我的 AuthRedirect Uri 需要在 Azure AD 中注册为我的应用程序注册中的 RedirectUri。

所以这是loginRedirect() 生命周期,我不知道,并且浪费了一天的时间来整理:

  1. /UserProfile(或某些页面)调用登录请求
  2. 请求调用handleRedirectPromise()(它使用有关发出请求的位置以及交互状态的信息设置 MSAL,如果您不完成该过程,稍后将会困扰您)
  3. 然后调用loginRedirect(loginRequest)
  4. -> 用户被重定向,完成登录
  5. Azure redir 返回 -> /AuthRedirect
  6. /AuthRedirect 调用handleRedirectPromise()转发到 -> /UserProfile
  7. /UserProfile 调用handleRedirectPromise()它来实际处理令牌并在内部调用 setActiveAccount() 将您的用户保存到会话中。

当当。蛮好玩的。并且在文档中根本没有解释。

因此,您收到交互进行中错误的原因是因为您认为您已完成第 6 步。不! 第 7 步是interaction_in_progress确定并清理该状态的地方,以便后续调用不会在该状态上出错!

最后的想法:

如果您希望用户始终从指定的登录页面开始/结束(并且其本身就是注册的重定向 Uri),我想这些步骤将会减少(不会像此处的步骤 6 那样进行转发)。就我而言,我希望用户重定向回他们可能因会话过期而退出的任何地方。所以我发现在任何地方调用每个页面加载都更容易handleRedirectPromise(),以防所述页面需要完成身份验证。或者,我可以将自己的重定向逻辑构建到专用的登录页面中,该页面可以将用户带回点击之前的位置。只是对于 MSAL,我不知道该过程是在请求页面上完成的,而不是包含在我的 AuthRedirect 页面中,这就是让我感到困扰的地方。

现在,如果我们能让 MS 就 MSAL 的微妙和关键性质提供更好的文档,并提供一个 Vue 插件(为什么只有 Angular 和 React 获得所有荣耀?:)),那就太好了!


小智 15

您可以在打开登录弹出窗口之前清除浏览器存储:

let msalInstance: PublicClientApplication = this._msauthService.instance as PublicClientApplication;
msalInstance["browserStorage"].clear();
Run Code Online (Sandbox Code Playgroud)


jmi*_*mig 14

在开发过程中,由于需要更正的编码问题,您可能会将登录流程置于进度状态。您可以通过从浏览器中删除 msal.interaction.status cookie 来解决眼前的问题。当然,如果此问题仍然存在,那么您需要使用本页建议的其他解决方案之一来纠正问题。

  • 通过额外的支持信息可以改进您的答案。请[编辑]添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以[在帮助中心](/help/how-to-answer)找到有关如何写出好的答案的更多信息。 (3认同)

Smi*_*ers 7

msalInstance.loginRedirect(loginRequest);
Run Code Online (Sandbox Code Playgroud)

上面的这段代码接下来会做:

  1. 查看会话存储的密钥 msal.[clientId].interaction.status 和重定向过程所需的其他临时值。如果这样的键存在并且它的值等于 'interaction_in_progress' 错误将被抛出。
  2. 在会话存储中创建条目 msal.[clientId].interaction.status = interact.status
  3. 将用户重定向到 auth-page。

如果登录成功,用户将被重定向到带有您的代码的初始页面,并通过 1-3 个步骤并会捕获错误;

下面的这段代码删除了会话存储中的所有临时值并完成了身份验证重定向流程,但它是异步的,永远不会完成。

   msalInstance.handleRedirectPromise()
    .then(res=>{
      console.log(res)
    })
    .catch(err => {
      console.error(err);
    });
Run Code Online (Sandbox Code Playgroud)

解决方案将是

// Account selection logic is app dependent. Adjust as needed for different use cases.
// Set active acccount on page load
const accounts = msalInstance.getAllAccounts();
if (accounts.length > 0) {
  msalInstance.setActiveAccount(accounts[0]);
}

msalInstance.addEventCallback((event) => {
  // set active account after redirect
  if (event.eventType === EventType.LOGIN_SUCCESS && event.payload.account) {
    const account = event.payload.account;
    msalInstance.setActiveAccount(account);
  }
}, error=>{
  console.log('error', error);
});

console.log('get active account', msalInstance.getActiveAccount());

// handle auth redired/do all initial setup for msal
msalInstance.handleRedirectPromise().then(authResult=>{
  // Check if user signed in 
  const account = msalInstance.getActiveAccount();
  if(!account){
    // redirect anonymous user to login page 
    msalInstance.loginRedirect();
  }
}).catch(err=>{
  // TODO: Handle errors
  console.log(err);
});
Run Code Online (Sandbox Code Playgroud)

  • 我在 MS 文档中没有看到任何类似的提及。为了让最基本的事情发挥作用,必须来到 Stackoverflow,这似乎很荒谬。感谢您发布此内容...但是您奇迹般地想出了这个! (29认同)
  • 我不敢相信 MS 为实现 B2C 身份验证而变得多么复杂。有数十个不同的文档页面和代码示例,其中包含不同且相互冲突的信息。以及互联网上不同的随机解决方案来找出最基本的功能。但它们都没有完全起作用。我*真的*想切换到 Auth0 或 Cognito。这太糟糕了!!!!!!!!!! (18认同)
  • 仍然不适合我。OP 的错误仍然存​​在。尝试在 NextJS 应用程序上简单地实现 Azure AD B2C,这是我一年多来做过的最困难的事情。 (5认同)
  • @dapug - 我正在 GitHub 上阅读源代码,因为我遇到了同样的问题。 (3认同)
  • 这是提示:https://learn.microsoft.com/en-us/azure/active-directory/develop/msal-js-initializing-client-applications (2认同)