【问题标题】:IdentityServer4 authenticate each client separatelyIdentityServer4 分别对每个客户端进行身份验证
【发布时间】:2021-09-20 11:02:51
【问题描述】:

我使用两个不同的客户端。 IdentityServer4 提供 API 保护和登录表单。我可以配置客户端以避免单点登录。我的意思是,即使我登录了第一个客户端,我也需要登录第二个客户端。

我的 ID4 配置:

internal static IEnumerable<Client> GetClients(IEnumerable<RegisteredClient> clients)
{
    return clients.Select(x =>
    {
        var scopes = x.AllowedScopes.ToList();
        scopes.Add(IdentityServerConstants.StandardScopes.OpenId);
        scopes.Add(IdentityServerConstants.StandardScopes.Profile);
        scopes.Add(IdentityServerConstants.StandardScopes.OfflineAccess);

        var client = new Client
        {
            ClientId = x.Id,
            ClientName = x.Name,
            AllowedGrantTypes = GrantTypes.Hybrid,

            RequireConsent = false,

            RefreshTokenExpiration = TokenExpiration.Sliding,
            RefreshTokenUsage = TokenUsage.ReUse,

            ClientSecrets = {new Secret(x.Secret.Sha256())},
            RedirectUris = new[] {$"{x.Url}/signin-oidc"},
            PostLogoutRedirectUris = new[] {$"{x.Url}/signout-callback-oidc"},

            UpdateAccessTokenClaimsOnRefresh = true,

            AllowAccessTokensViaBrowser = true,
            AllowedScopes = scopes,
            AllowedCorsOrigins = {x.Url},
            AllowOfflineAccess = true
        };

        return client;
    });
}

所有客户端的注册码都一样(可能是个问题):

const string oidcScheme = "oidc";
const string coockieScheme = CookieAuthenticationDefaults.AuthenticationScheme;

services.AddAuthentication(options =>
{
    options.DefaultScheme = coockieScheme;
    options.DefaultChallengeScheme = oidcScheme;
})
    .AddCookie(coockieScheme)
    .AddOpenIdConnect(oidcScheme, options =>
    {
        options.SignInScheme = coockieScheme;

        options.Authority = identitySettings.Authority;
        options.RequireHttpsMetadata = false;

        options.ClientId = identitySettings.Id;
        options.ClientSecret = identitySettings.Secret;

        options.ResponseType = "code id_token";

        options.Scope.Add("offline_access");
        foreach (var scope in identitySettings.Scopes)
        {
            options.Scope.Add(scope);
        }

        options.GetClaimsFromUserInfoEndpoint = true;
        options.SaveTokens = true;
    });

任何帮助都会很有用。

【问题讨论】:

    标签: authentication single-sign-on identityserver4 asp-net-core-spa-services


    【解决方案1】:

    只要您在同一个浏览器会话中,并且您的应用具有相同的权限(使用相同的身份服务器),这将无法正常工作。

    我将向您解释原因 - 一旦您从第一个客户端登录,Identity Server 就会创建一个 cookie(其中包含所需的所有相关数据)。

    现在是第二个客户端 - 授权(身份服务器)与发出 cookie 的相同。因此,Identity Server 会识别您的会话,看到您已经通过身份验证并将您重定向到第二个客户端,而不要求提供凭据。

    毕竟这是 Identity Server 的想法:

    IdentityServer4 是用于 ASP.NET Core 2 的 OpenID Connect 和 OAuth 2.0 框架。

    它在您的应用程序中启用以下功能:

    身份验证即服务

    所有应用程序(网络、本机、移动、服务)的集中登录逻辑和工作流程。 IdentityServer 是经过官方认证的 OpenID Connect 实现。

    单点登录/注销

    在多种应用程序类型上单点登录(和注销)。

    还有更多……

    这是来自official documentation

    您必须为每个客户端选择不同的权限(Identity Server 实例),或者重新考虑 Identity Server 在这种情况下是否适合您。

    不推荐

    我不建议这样做,因为它有点覆盖了 Identity Server 的 SSO 理念,但是如果你仍然想这样做 - 如果你覆盖 IProfileService,你可以实现你想要的。有一个方法public Task IsActiveAsync(IsActiveContext context),这个上下文有一个属性IsActive,它确定当前主体是否在当前客户端中处于活动状态。

    您可以尝试在此处实现一些自定义逻辑,并根据用户 ID (context.Subject.GetSubjectId()) 和客户端 ID (context.Client.ClientId) 来确定用户是否已登录此客户端。

    编辑

    在您发表评论之后 - 这不是来自 Identity Server 的 OOTB(如果我可以这样说的话),但幸运的是您有一个选择。

    Policy based authorization 每个客户。像这样,您的用户可以针对 Identity Server(及其所有客户端)验证,但只有特定客户端会授权他。您可以将此策略视为自定义授权属性(或多或少)。

    像这样,用户将在客户端收到未经授权的信息,而他.. 未经授权。希望这能解决问题并有所帮助:)

    【讨论】:

    • 感谢您的回答。但是,如果我需要实现多个内部/公共应用程序并确保只有特定用户可以访问特定客户端怎么办?看起来很普通,我认为ID4应该提供一个内置的机制来实现这个。
    • 在阅读 IS 文档和 github 讨论后,我希望完全理解 SSO 方法。就我而言,我可以将角色与我的客户端应用程序一起使用,因此我们将身份验证 (IS SSO) 和授权 (角色) 分开。
    • 没错。这是做事的正确方法。 IS 的工作是认证,客户端的工作是授权,这东西应该分开。
    • 我明白你的意思,但我可以争辩说,对用户进行身份验证应该考虑到用户来自的客户端。我认为 IDSRV4 缺少一些东西。如果我们不希望这种 SSO 行为或能够将用户与客户/租户相关联,则应该有一个设置来禁用此 SSO 行为。不过感谢您的回答。这对我也很有帮助!
    • @Apollonas 您是否发现任何提到的有关 SSO 行为的细微差别?
    【解决方案2】:

    您可以从所有客户端设置prompt=login

    prompt
    none - no UI will be shown during the request. If this is not possible (e.g. because the user has to sign in or consent) an error is returned
    
    login - the login UI will be shown, even if the user is already signed-in and has a valid session
    

    https://identityserver4.readthedocs.io/en/latest/endpoints/authorize.html

    这将强制第二个客户端重新登录,而不管前一个客户端的登录状态如何。

    【讨论】:

      猜你喜欢
      • 2020-12-20
      • 1970-01-01
      • 1970-01-01
      • 2012-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-30
      • 1970-01-01
      相关资源
      最近更新 更多