首页 > 解决方案 > IdentityServer 使用外部提供者登录不适用于 long login_hint 或 acr_values

问题描述

在我OpenIdConnectAuthenticationOptions我设置了OpenIdConnectAuthenticationNotifications RedirectToIdentityProvider

它看起来像这样:

RedirectToIdentityProvider = n =>
{
    if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.AuthenticationRequest)
    {
        n.ProtocolMessage.LoginHint = "LoginHint";
        n.ProtocolMessage.AcrValues = "idp:CustomIdProvider";
    }
    return Task.FromResult(0);
}

在此示例中,我能够收到 LoginHint 并且一切正常。

现在,如果我将 设置LoginHint为大约 1000 个字符长的内容(同样会发生AcrValues),IdentityServer 会显示一条错误消息:

确定您正在登录的应用程序时出错。返回应用程序并重试。

并且日志显示此消息:

找不到与登录 ID 匹配的 cookie

这只发生在LoginHint(或AcrValues)达到一定大小时

存储 cookie 或读取 cookie 时似乎有问题,可能它们太大了

我已经尝试/配置的内容:

客户端和服务器的Web 配置根据这个答案,所有这些值都应该足够高,我会在它工作时将它们降低到适当的值):

<system.web>
    <httpRuntime targetFramework="4.6.1" maxUrlLength="109990" maxQueryStringLength="100000" maxRequestLength="256000" />
</system.web>
<!--...-->
<requestFiltering>
    <requestLimits maxQueryString="100000" maxAllowedContentLength="1073741824" />
</requestFiltering>

InputLengthRestrictions中的IdentityServerOptions(同样的值应该足够了):

InputLengthRestrictions = new InputLengthRestrictions
{
    UserName = 51200,
    AcrValues = 51200,
    LoginHint = 51200
}

这是此问题的后续问题:向外部身份提供者发送自定义参数

编辑:

有关我的结构的更多信息:

我的客户收到一个令牌作为查询参数,它可能很长(大约 900 个字符)。
客户端现在使用以下选项重定向到 IdentityServer:app.UseOpenIdConnectAuthentication(options);

客户 Startup.cs:

RedirectToIdentityProvider = n =>
{
    if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.AuthenticationRequest)
    {
        var token = n.Request.Query.Get("token");
        if (token != null)
        {
            n.ProtocolMessage.Parameters.Add("token", token);
            n.ProtocolMessage.AcrValues = "idp:CustomIdP";
        }

    }
    return Task.FromResult(0);
}

其余的options都很基本

在我的 IdentityServer 上,我配置了AuthenticationOptions' IdentityProviders-Property,正如您在我的 IdServer 配置的摘录中看到的那样,我还将 ' -Property 设置InputLengthRestrictions为一个高值,只是为了安全起见:

IdentityServer Startup.cs:

IdentityServerOptions options = new IdentityServerOptions
{
    InputLengthRestrictions = new InputLengthRestrictions
    {
        RedirectUri = 51200,
        AcrValues = 51200,
        LoginHint = 51200
    },
    AuthenticationOptions = new AuthenticationOptions {

        CookieOptions = new IdentityServer3.Core.Configuration.CookieOptions
        {
            SessionStoreProvider = new SessionStoreProvider()
        },
        IdentityProviders = ConfigureIdentityProviders,
    }
};
idsrvApp.UseIdentityServer(options);

然后我配置我的 IdentityProviders,我的 IdentityProvider 使用Clients Startup.cs中指定的参数中的 Token 这对于短令牌来说很好,一切都按原样调用。

但是,如果令牌太长,它甚至不会走那么远。我的猜测是问题的根源在于OpenIdConnectAuthenticationHandler

编辑 2

为什么这么快就达到了极限:

显然,我的令牌被两次添加到对 IdentityServer 的请求中。

由于这个原因,cookie 的限制很快就达到了。

客户 Startup.cs:

RedirectToIdentityProvider = n =>
{
    if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.AuthenticationRequest)
    {
        var token = n.Request.Query.Get("token");
        if (token != null)
        {
            n.ProtocolMessage.Parameters.Add("token", token);
            n.ProtocolMessage.AcrValues = "idp:CustomIdP";
        }

    }
    return Task.FromResult(0);
}

在这里,我从 QueryString 中获取令牌。但我在这里错过的是,n.ProtocolMessage已经包含了包含tokenRequestUri的as State 参数。所以令牌被发送两次到 IdentityServer。如果我从-Parameter 中删除令牌(这是正确的做法,因为我在重定向回来时不需要它)并添加它,因为它确实按预期将其发送到 IdentityServer。stateAcrValue

但问题仍然存在。

如果 Token 真的很长怎么办?

标签: c#asp.netasp.net-mvcowinidentityserver3

解决方案


我不能确定,但​​是,这听起来可能是最大 cookie 大小问题。Cookie 在大多数浏览器
中只能存储 4096 个字节,例如,如果 cookie 以 UTF-32 存储,那么 1024 个字符将占用所有空间,并且您的 cookie 将被截断。

您可能想尝试覆盖AuthenticationOptions中的CookieOptions属性之一。

CookieOptions类中,您可以提供IAuthenticationSessionStoreProvider。根据对该属性的评论,它可能是您正在寻找的解决方案,至少您可以调试出问题所在。

/// <summary>
///   An optional container in which to store the identity across requests.
///   When used, only a session identifier is sent
///     to the client. This can be used to mitigate potential problems 
///     with very large identities.
/// </summary>
public IAuthenticationSessionStoreProvider SessionStoreProvider { get; set; }

IAuthenticationSessionStoreProvider 没有默认实现,但您可以查看它在AuthenticationSessionStoreWrapper中的使用方式

AuthenticationSessionStoreWrapper如果您添加提供程序,它会包含在 an 中:

static IAuthenticationSessionStore GetSessionStore(IAuthenticationSessionStoreProvider provider)
{
    return provider != null ? new AuthenticationSessionStoreWrapper(provider) : null;
}

推荐阅读