ClientAuthError:令牌调用在隐藏的 iframe 中被阻止

Posted

技术标签:

【中文标题】ClientAuthError:令牌调用在隐藏的 iframe 中被阻止【英文标题】:ClientAuthError: Token calls are blocked in hidden iframes 【发布时间】:2020-05-12 20:26:46 【问题描述】:

我正在构建一个使用 MSAL.js 作为 Azure Active Directory 客户端的 javascript SPA。

当为我的 API 请求访问令牌时

var requestObj = 
  scopes: ["api://MyApi/Access"]
;
msalUserAgent.acquireTokenSilent(requestObj ) 

Msal 在内部为自己创建一个 iframe 来处理请求,然后给出以下关于在不支持的 iframe 内操作的错误:

ClientAuthError: Token calls are blocked in hidden iframes
    at ClientAuthError.AuthError [as constructor] (webpack-internal:///./node_modules/msal/lib-es6/error/AuthError.js:26:28)
    at new ClientAuthError (webpack-internal:///./node_modules/msal/lib-es6/error/ClientAuthError.js:111:28)
    at Function.ClientAuthError.createBlockTokenRequestsInHiddenIframeError (webpack-internal:///./node_modules/msal/lib-es6/error/ClientAuthError.js:192:16)
    at Function.WindowUtils.blockReloadInHiddenIframes (webpack-internal:///./node_modules/msal/lib-es6/utils/WindowUtils.js:206:90)
    at eval (webpack-internal:///./node_modules/msal/lib-es6/UserAgentApplication.js:474:77)
    at new Promise (<anonymous>)
    at UserAgentApplication.acquireTokenSilent (webpack-internal:///./node_modules/msal/lib-es6/UserAgentApplication.js:472:16)
    at Object.ensureUserLoggedIn (webpack-internal:///./src/services/ActiveDirectoryService.js:93:19)
    at eval (webpack-internal:///./src/main.js:36:89)
    at Module../src/main.js (http://localhost:8080/js/app.js:1178:1)

我的网页似乎仍然按预期工作,但我真的不喜欢携带未解决的错误,所以我试图找出问题的原因。

试图解决这个看起来很像我的问题的I have found this issue on github。它确认acquireTokenSilent 确实创建了一个iFrame,该iFrame 重定向回主spa 应用程序(然后尝试登录并请求令牌......所以基本上是无休止的递归)。这就是它被阻止的原因。

其中一个建议是将redirectUri指定为没有我尝试过的MSAL的页面,但没有成功

 request = 
      scopes:  ["api://MyApi/Access"],
      redirectUri: "http://localhost:8080/token-landing.html"
    ;
    // 
    return msalUserAgent.acquireTokenSilent(request);

这并没有解决问题,而且很难看出是否使用了重定向。其他建议是在我尝试的所有地方检查 url 中的“#”并获取一个不太好的令牌,因为“#”在 SPA 网站中很常见。

【问题讨论】:

我们做的一个常见的解决方案是在应用的根目录中添加一个检查我们是否在 iframe 中,如果是这种情况则立即停止渲染。 是的,这似乎可行。我将我的初始化代码包装在 window.self === window.top if (window.self === window.top) //如果我们在 iframe 中则不渲染 //修复由 msal.js 引起的登录循环创建重定向回应用程序的 iframe new Vue( router, store, render: h => h(App), created: ActiveDirectoryService.ensureUserLoggedIn() ).$mount("#app"); 我仍然对为什么 redirectUri 没有工作感到困惑.. 解决方案——添加一个空白的 html 页面并将其用作 redirectUri——this other issue page 上的建议对我有用。我正在使用弹出登录类型。 redirectUri真的叫tokenRedirectUrl吗?并通过主要选项?像这样 sn -p ``` const options = loginType: LoginType.Redirect, tokenRefreshUri: window.location.origin + '/auth.html', ``` 【参考方案1】:

来源:https://github.com/lukezirngibl/msal-react-v2


enum Scopes 
  OPEN_ID = 'openid',
  CUSTOM_SCOPE = 'api://XXXX-XXXX-XXXXXX-XXXXX/all',
  USER_READ = 'User.Read',


const config = 
  auth: 
    clientId: 'XXXXXX-XXXXXX-XXXXXX-XXXXX-XXXXX', // clientId or appId
    redirectUri: 'http://localhost:3000',         // redirectUri
    authority: undefined,                         // Optional
  ,
  cache: 
    cacheLocation: 'localStorage',
    storeAuthStateInCookie: true,
  ,


const 
  AuthProvider,   // Use once!
  getAccessToken, // Can use to inject access tokens elsewhere in your app
  msalClient,     // Use elsewhere for msalClient.logout() and other client functions
  graphClient,    // Use for graph client api calls
  useAccount,     // React Hook to give access to account info in child components
 = configureMsal(
  config,                                                // Required
  msalScopes: [Scopes.OPEN_ID, Scopes.CUSTOM_SCOPE],     // Optional (But Recommended)
  graphClientScopes: [                                   // Optional (But Recommended
    Scopes.USER_READ,
  ],
)

const App = () => (
  <AuthProvider
    render=( state, account ) =>
      state === AuthProviderState.Success ? (
        <div>Logged in as account.username </div>
      ) : (
        <div>Loading..</div>
      )
    
  />
);

【讨论】:

您能否详细说明解决方案是什么?欢呼 你为什么要发布这个?这里有什么可以解决问题的细节吗?

以上是关于ClientAuthError:令牌调用在隐藏的 iframe 中被阻止的主要内容,如果未能解决你的问题,请参考以下文章

从客户端隐藏访问令牌

JWT 令牌刷新后返回重新调用

页面中所有表单的 Laravel 5 CSRF 全局令牌隐藏字段

从javascript传递到web api 2时如何隐藏或保护令牌

如何在角度和弹簧应用程序中隐藏访问令牌?

屏蔽/隐藏 github 访问令牌