OIDC客户端对多租户的支持-OIDC客户端抛出“在存储中找不到匹配状态”

时间:2020-05-25 13:57:46

标签: vue.js asp.net-core identityserver4 openid-connect identity

我正在为vue js客户端应用程序使用.net核心身份服务器4身份验证。我支持多租户。我在客户端使用oidc客户端Java脚本库进行身份验证。

客户端配置将是这样

authority: 'http://identity.identityserver.com/',
"redirect_uri": "http://app.clientapp.com/callback",
"client_id": "app1",
"grant_type": "authorization_code",
"client_secret": "secret_code",
"response_type": "code",
"scope": "openid profile web.api",
"post_logout_redirect_uri": "http://app.clientapp.com/logoutSuccess",

身份服务器配置将是这样

new Client
            {
                ClientId = "app1",
                ClientName = "Vue JS APP",
                ClientSecrets = new List<Secret> { new Secret("secret_code") },
                AllowedGrantTypes = GrantTypes.Code,
                AllowAccessTokensViaBrowser = true,
                AlwaysIncludeUserClaimsInIdToken = true,
                AlwaysSendClientClaims = true,
                RedirectUris = { "http://app.clientapp.com/callback" },
                RequireConsent = false,
                PostLogoutRedirectUris = { "http://app.clientapp.com/callback/logoutSuccess" },
                AllowedScopes =
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    "web.api",
                },
},

这按预期工作,没有任何问题。它重定向到身份服务器,弹出登录窗口,输入凭据后,成功重定向到http://app.clientapp.com/callback

我的要求是,基于用户登录名,我必须将用户重定向到他的子域,即支持多租户。例如,如果用户“ user1”的承租人是tenant1,即使配置的回调URL为http://app.clientapp.com/callback,则在成功重定向后,用户也必须重定向到http://tenant1.clientapp.com/callback。我已经在身份服务器中进行了必要的更改,以使用IRedirectUriValidator覆盖它。并且它正在重定向回http://tenant1.clientapp.com/callback。但是问题是,客户端的oidc-client抛出“在存储中找不到匹配状态”。

任何人都可以在这个问题上提供帮助。

先谢谢了。

1 个答案:

答案 0 :(得分:0)

这并不特别适用于您的情况,但是,对于其他人在这个特殊的oidc-client错误上head之以鼻,觉得值得一试。

我们发现了导致此错误间歇出现在日志中的两个其他原因。在我们的例子中,在oicd登录回调内部的oidc-client-js方法signinRedirectCallback()期间引发了“在存储中找不到匹配状态”错误。

原因:

  1. 系统时钟的用户设置为与当前实际时间相差5分钟以上(在oidc-client-js中,clockSkew默认为5分钟)

  2. 用户正在共享和重复使用由Identity Server生成的带有安全参数的唯一生成的登录URL

    /login?ReturnUrl=https%3A%2F%2Fae-xxxxxx%2Fauthorize%2Fcallback%3Fclient_id%3Dxxxxxx%26redirect_uri%3Dhttps%253A%252F%252Fxxxxxxxx.com%252Fsignin-oidc%26response_type%3Dcode%26scope%3Dopenid%2520profile%2520email%26state%3D3b6da3263b9e47c3a954c1d6b149337f%26code_challenge%asagasgsagas-Wf8VWWWRWiGvCPfcu3MdDFhA%26code_challenge_method%3DS256%26response_mode%3Dquery

我们最终在包裹oidc-client-js的AuthContext中捕获并报告了错误,如下所示:

signinRedirectCallback = async () => {
  try {
    await this.UserManager.signinRedirectCallback();
  } catch (error) {
    Sentry.captureException(error, {
      level: "warning",
    });

    // clearing state and storage 
    // may not be necessary, 
    // but it seems reasonable
    this.UserManager.clearStaleState();
    localStorage.clear();

    throw new Error(error);
  }
};

然后在signin-oidc回调中,捕获错误并将用户引导至错误页面:

import { useEffect, useContext } from "react";
import { useHistory } from "react-router-dom";
import AuthContext from "contexts/auth";

export default () => {
  const auth = useContext(AuthContext);
  const history = useHistory();

  useEffect(() => {
    auth.signinRedirectCallback().catch((error) => {
      history.replace("/error?code=login_callback_error");
    });
  }, [auth, history]);

  return "";
};