IdentityServer4 authenticate each client separately

不想你离开。 提交于 2020-01-13 19:29:11

问题


I use two different clients. The IdentityServer4 provides API protections and log in form. Can I configure clients to avoid single sign on. I mean that even if I logged in the first client I need to log in the second client too.

My ID4 configuration:

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

All client have the same register code (Maybe it is a problem):

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

any help will be useful.


回答1:


As long as you are in the same browser session, and your apps are having the same authority (are using the same Identity Server) this will not work.

I'll explain you why - once you log in from the first client, Identity Server creates a cookie (with all the relevant data needed in it).

Now comes the second client - the authority (the Identity Server) is the same that has issued the cookie. So Identity Server recognizes your session, sees that you are already authenticated and redirects you to the second client, without asking for credentials.

After all, this is the idea of Identity Server:

IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core 2.

It enables the following features in your applications:

Authentication as a Service

Centralized login logic and workflow for all of your applications (web, native, mobile, services). IdentityServer is an officially certified implementation of OpenID Connect.

Single Sign-on / Sign-out

Single sign-on (and out) over multiple application types.

and more....

This is from the official documentation.

You have to either go for different authorities (Identity Server instances) for each client, or re-think is Identity Server the right solution for you in this case.

NOT RECOMMENDED

I'm not recommending this, because it kind of overrides the SSO idea of Identity Server, however if you still want to do it then - you can achieve what you want if you override the IProfileService. There is a method public Task IsActiveAsync(IsActiveContext context) and this context has a property IsActive which determines if the current principal is active in the current client.

You can try and implement some custom logic here, and based on the user ID (context.Subject.GetSubjectId()) and the client id (context.Client.ClientId) to determine if the user is already logged in this client or not.

EDIT

After your comment - this is something that doesn't come OOTB from Identity Server (if I can say it like this), but luckily you have an option.

Policy based authorization per client. Like this, your user can authenticate against Identity Server (and all of its clients), but only the specific clients will authorize him. You can treat this policies as a custom authorize attribute (more or less).

Like this, a user will receive unauthorized in clients, where he.. is not authorized. Hope that this clears the thing and helps :)



来源:https://stackoverflow.com/questions/49880489/identityserver4-authenticate-each-client-separately

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!