浏览器身份验证错误:interaction_in_progress:目前正在与azure/msal-browser@2.11.2进行交互。

45

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

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.

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)
}

异常

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
9个回答

37
msalInstance.loginRedirect(loginRequest);

上述代码的作用如下:

  1. 查找会话存储中是否存在键为msal.[clientId].interaction.status以及其他必需的重定向过程临时值。如果存在这样的键并且其值等于“interaction_in_progress”,则会抛出错误。
  2. 在会话存储中创建条目msal.[clientId].interaction.status = interaction.status
  3. 将用户重定向到身份验证页面。

如果登录成功,则用户将被重定向回具有您的代码的初始页面,并经历1-3个步骤并捕获错误;

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

   msalInstance.handleRedirectPromise()
    .then(res=>{
      console.log(res)
    })
    .catch(err => {
      console.error(err);
    });

解决方案将是

// 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);
});

27
在微软文档中,我没有看到任何类似这样的提及。不得不来Stackoverflow才能让最基本的东西运作起来,这似乎很荒谬。感谢您发布这个...不管你是如何神奇地想出来的! - dapug
2
这是提示:https://learn.microsoft.com/zh-cn/azure/active-directory/develop/msal-js-initializing-client-applications - rubeonline
3
@dapug - 我在GitHub上阅读源代码,因为我遇到了相同的问题。 - shevchenko-vladislav
5
仍然无法正常运行,我仍然遇到了原始帖子中的错误。 我正在尝试在NextJS应用程序上简单实现Azure AD B2C,这是我一年多以来做过的最难的事情。 - Alexandre Moreira
16
我简直无法相信微软让B2C认证实现变得如此复杂。有数十个不同的文档页面和代码示例,提供着不同且相互矛盾的信息。而在互联网上,也有不同的随机解决方案来解决最基本的功能。但是,这些都不能完全发挥作用。我真的很想转向Auth0或Cognito。这太烦人了!!!!!! - suntzu
你们有没有想出NextJS的解决方案?我在文档上花费的时间让我每次都感到心痛。 - SthaSAM

23

我相信这是正确的答案和设置方法,其他人在这里给了我解决问题的线索。

简而言之,按照以下方式设置您的代码:

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


// 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();
  }
}

如果您正确操作,就不需要使用@shevchenko-vladislav共享的代码,其中必须由您手动执行setActiveAccount()。请记住,在调用此函数的任何位置都要验证所有的async/await!请注意,我在我的主要authredirect.vue文件中没有使用handleRedirectPromise().then()或其他任何东西。只是在加载时使用handleRedirectPromise()

Stackoverflow上的其他解决方案建议检查并从会话中删除交互状态。嗯,不行!如果在登录后留下该状态,则表示过程未正确完成!MSAL会自我清理!

完整细节:

了解MSAL在其整个生命周期中实际执行的操作非常重要(特别是红色路径与弹出窗口不同),但遗憾的是文档做得不够好。我发现这个小“副笔记”非常非常重要:

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

如果您从不是您的redirectUri的页面调用loginRedirectacquireTokenRedirect,则需要确保在重定向页面以及启动重定向的页面上都调用和等待handleRedirectPromise。这是因为重定向页面将启动返回到最初调用loginRedirect的页面,并且该页面将处理令牌响应。
换句话说,你必须在重定向页面和发出登录请求的页面在页面加载时(或在我的情况下,在mounted()内)调用handleRedirectPromise()
在我的例子中,我有以下两个网址:
  • http://localhost:8080/authredirect *
  • http://localhost:8080/userprofile
只需要注册AuthRedirect Uri作为Azure AD应用程序注册的RedirectUri。
下面是loginRedirect()生命周期,在文档中并没有解释清楚:
  1. /UserProfile(或某些页面)发起登录请求
  2. 请求调用handleRedirectPromise()(设置MSAL与请求位置和交互状态相关的信息,否则在后续过程中会产生问题)
  3. 然后调用loginRedirect(loginRequest)
  4. ->用户被重定向,完成登录
  5. Azure重定向回-> /AuthRedirect
  6. /AuthRedirect调用handleRedirectPromise(),将其转发到- > /UserProfile
  7. /UserProfile调用handleRedirectPromise(),实际处理令牌并在内部调用setActiveAccount()以将用户保存到会话。
所以说,如果您认为在第6步已经完成了所有操作,那么您将会收到interaction_in_progress错误。NOPE!第7步是解决和清除interaction_in_progress状态的关键,这样后续调用就不会被它挂起!
如果您有一个指定的登录页面,您希望用户始终从该页面开始/结束(并且它本身是注册的重定向URI),我想这些步骤将被减少(不像这里第6步中转)。在我的情况下,我希望用户重定向回到他们可能由于会话过期而被弹出的任何地方。因此,我发现在每个页面加载时调用handleRedirectPromise()更容易,以防所述页面需要完成身份验证。或者,我可以构建自己的重定向逻辑到专用登录页面,可以将用户放回到他们之前到达该页面的位置。只是对于MSAL而言,我不知道该过程正在请求页面上完成,而不是包含在我的AuthRedirect页面中,这就是让我困扰的原因。
如果我们能够得到微软提供有关MSAL的精细和关键性质的更好文档,并提供Vue插件(为什么只有Angular和React才能获得全部荣耀?:)),那就太棒了!

1
哇,这太简单了,而且它还起作用了。在我的Angular应用程序中,我只需要在ngOnInit()方法中添加一行代码“this.msalService.instance.handleRedirectPromise();”就可以了! - Caustix
1
这个人在 https://www.youtube.com/watch?v=TkCKqeYjpv0 的第16分钟也讲解了如何在Angular应用程序中实现此功能。 - Caustix
通过dapug的代码,我保住了我的理智。不过为了适合我的需求,我稍微调整了一下。 - Thomas
我花了很多时间试图将一个不太好的弹出式流程改成更顺畅的重定向流程。完全同意这个帖子中被接受的答案有些过度,我只是在我的异步signin()函数里加了一句"await msalInstance.handleRedirectPromise();",结果就像梦一样顺利。 - undefined

14

在打开登录弹出框之前,您可以清除浏览器存储。

let msalInstance: PublicClientApplication = this._msauthService.instance as PublicClientApplication;
msalInstance["browserStorage"].clear();

msalInstance["browserStorage"].clear(); 做到了。谢谢! - GarryOne
这个可以运行但是会导致测试失败。 - Jason Foglia
这个答案真是太棒了!我之前遇到了和其他人一样的代码问题,在一个旧应用中运行正常,但在一个新应用中却出现了错误。使用这个浏览器存储清除函数解决了我的问题。非常感谢! - undefined
重新审视这个问题,对于MSAL版本3来说,这已经不再是一个解决方案了。 - undefined

13
在开发过程中,由于需要纠正的编码问题,可能会导致您在登录流程中停留在进度状态。您可以通过从浏览器中删除msal.interaction.status cookie来清除立即问题。当然,如果问题持续存在,则需要使用本页面建议的其他解决方案来纠正问题。

3
您的回答可以通过提供更多支持性信息来改进。请[编辑]以添加更多详细信息,例如引用或文献资料,以便他人可以确认您的回答是否正确。您可以在帮助中心中了解有关如何撰写良好答案的更多信息。 - Community
我来这里是为了发表与jmig相同的评论。删除cookies对我有帮助。 我对dapug的解决方案很感兴趣,它是有道理的,但与文档中推荐的远不一样。至少到目前为止,我还没有需要在我的代码库周围粘贴handleRedirectPromise()! - Mick Buckley
如果有帮助的话,我认为交互正在进行的状态进入了我的 cookie,因为我曾经错误地设置了“navigateToLoginRequestUrl: true”。 - Mick Buckley
进一步澄清,我不需要调用handleRedirectPromise,因为它已经为我完成了。我正在使用msal-react(v1.0.1)。它在MsalProvider内的useEffect hook中调用handleRedirectPromise。 - Mick Buckley

0

我发现在 msal.js v2 中,你可以在纯 .js 代码中检查交互状态,以查看是否存在正在进行的交互,如果出于某种原因需要这样做:

const publicClientApplication = new window.msal.PublicClientApplication(msalConfig);

var clientString = "msal." + msalConfig.clientId + ".interaction.status";

var interaction-status = publicClientApplication.browserStorage.temporaryCacheStorage.windowStorage[clientString]

我正在使用的 MSAL 2.5.5 版本的 browserStorage 是受保护的。 - Jason Foglia

0

更新 @azure/msal-browser@2.21.0。


0

针对使用 Azure/Active Directory 的用户:

我的问题并不在于我的代码,而是在于停用“访问令牌(用于隐式流)”设置,该设置位于Active Directory > 身份验证 > 隐式授权和混合流部分。

在将正确的重定向 URI 放入Web部分之后:

ex: https://example.com/.auth/login/aad/callback

在将正确的重定向URI放入单页应用程序部分之后:

ex: https://example.com

ex: https://localhost:4200

最后一步是确保您禁用我在开头提到的访问令牌:

Disable the Access tokens setting found in Implicit grant and hybrid flows section in the Active Directory Authentication

当我将我的应用程序从.NET5迁移到.NET6并将先前的Angular身份验证转移到MSAL时,这个设置已经为我检查过了(两者都被检查)。取消选中此设置后,一切都正常工作。


-1

这可能不是一个完美的解决方案。但至少在Vue.js中可以工作。

在您的acquireToken()逻辑旁边,添加以下内容

// Check Local or Session storage which may have already contain key 
// that partially matches your Azure AD Client ID
let haveKeys = Object.keys(localStorage).toString().includes('clientId')
// That error will just go away when you refrest just once
let justOnce = localStorage.getItem("justOnce");

if (haveKeys && !justOnce) {
  localStorage.setItem("justOnce", "true");
  window.location.reload();
} else {
  localStorage.removeItem("justOnce")
}

-1

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接