Redirecting url from Identity server 4 is not beha

2020-03-27 05:57发布

问题:

Note : After resolving the redirection issue i had an another issue that is getting an error "Cannot cast Newtonsoft.Json.Linq.JArray to Newtonsoft.Json.Linq.JToken". So in my answer I have provided the correct solution for both.

I have identity server project and the client project, everything works up to authentication without any issues and even it redirects to the correct client url but the url ex : "https://localhost:44309/signin-oidc" gives the blank page.

Note : SSl enabled for Identity Server and Client application.

It is authenticating the user as expected as you can see below in the screen shot. My Identity server contains the following config values for client.

                // OpenID Connect hybrid flow and client credentials client (MVC)
            new Client
            {
                ClientId = "mvc",
                ClientName = "MVC Client",
                AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
                ClientSecrets =
                {
                    new Secret("secret".Sha256())
                },

                RedirectUris = { /*"http://localhost:5002/signin-oidc",*/"https://localhost:44309/signin-oidc" },
                PostLogoutRedirectUris = { /*"http://localhost:5002/signout-callback-oidc",*/"https://localhost:44309/signout-callback-oidc" },

                AllowedScopes = 
                {
                    IdentityServerConstants.StandardScopes.OpenId,
                    IdentityServerConstants.StandardScopes.Profile,
                    //"api1"
                },
                AllowOfflineAccess = true
            }

The startup.cs is as follows.

        public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        // configure identity server with in-memory stores, keys, clients and scopes
        services.AddIdentityServer()
            .AddDeveloperSigningCredential()
            .AddInMemoryIdentityResources(Config.GetIdentityResources())
            .AddInMemoryApiResources(Config.GetApiResources())
            .AddInMemoryClients(Config.GetClients())
            .AddTestUsers(Config.GetUsers());

        services.AddAuthentication()
            //.AddGoogle("Google", options =>
            //{
            //    options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

            //    options.ClientId = "434483408261-55tc8n0cs4ff1fe21ea8df2o443v2iuc.apps.googleusercontent.com";
            //    options.ClientSecret = "3gcoTrEDPPJ0ukn_aYYT6PWo";
            //})
            .AddOpenIdConnect("oidc", "dataVail Login", options =>
            {
                options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                options.SignOutScheme = IdentityServerConstants.SignoutScheme;

                options.Authority = "https://login.microsoftonline.com/d0e2ebcc-0961-45b2-afae-b9ed6728ead7";//"https://demo.identityserver.io/";
                options.ClientId = "f08cc131-72da-4831-b19d-e008024645e4";
                options.UseTokenLifetime = true;
                options.CallbackPath = "/signin-oidc";
                options.RequireHttpsMetadata = false;

                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role"
                };
            });
    }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseForwardedHeaders(new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
        });

        app.Use(async (context, next) =>
        {
            context.Request.Scheme = "https";
            await next.Invoke();
        });
        app.UseIdentityServer();

        app.UseStaticFiles();
        app.UseMvcWithDefaultRoute();
    }

Here is the startup.cs for my client app

        public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
            .AddCookie("Cookies")
            .AddOpenIdConnect("oidc", options =>
            {
                options.SignInScheme = "Cookies";

                options.Authority = "https://localhost:44392/";
                options.RequireHttpsMetadata = false;

                options.ClientId = "mvc";
                options.ClientSecret = "secret";
                options.ResponseType = "code id_token";

                options.SaveTokens = true;
                options.GetClaimsFromUserInfoEndpoint = true;

                //options.Scope.Add("api1");
                options.Scope.Add("offline_access");

            });
    }

Can anyone please try helping me to sort this out.

回答1:

I could resolved this with the help of Identity Server 4 folks. If any one come across this problem here is the solution.

I missed adding "UseAuthentication" in Configure the client MVC pipeline. So after adding that i was redirected as expected and then I had another issue as shown below.

System.InvalidCastException: Cannot cast Newtonsoft.Json.Linq.JArray to Newtonsoft.Json.Linq.JToken. at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler1.d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()

I'm getting this exception while connecting my application to IdentityServer4 with AzureAD as external authentication provider. My application is using Hybrid flow to connect to IdentityServer4. I get properly redirected to Azure, login, and code and id_tokens are properly issued. This exception is raised in my application when userInfo endpoint is invoked.

In order resolve this I had to remove the claim which has the name twice.

I confirmed that AAD sends two name claims. Removing one of them resolved the problem.

var namesClaim = externalUser.FindFirst(ClaimTypes.Name) ??
                             throw new Exception("Unknown names");

if (namesClaim!=null)
{
    claims.Remove(namesClaim);
}

Hope this may help someone.



回答2:

I had the same problem with having multiple roles. Here is the solution for it:

.AddOpenIdConnect("oidc", options =>
{
    // ...
    options.Scope.Add("roles");

    // ... using MapJsonKey instead of MapUniqueJsonKey for having 2 or more roles
    options.ClaimActions.MapJsonKey(claimType: "role", jsonKey: "role");
});