ASP.NET Identity in MVC client using IdentityServer causes loop

懵懂的女人 提交于 2019-12-11 17:09:11

问题


I have an Asp.NET Core application that uses IdentityServer for authentication.
This works fine.
Now I want to use ASP.NET Core Identity in my application for managing roles, claims, etc.

The documentation saysI should add service.AddIdentity ... for that.
However, when I add that in my client to the Startup.cs, the login with IdentityServer no longer works.

I will be redirected to IdentityServer, login and redirected back to the client (this works fine)
However, then my client throws an error about authorization and redirects to the IdentityServer again. This causes an endless loop

Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:44331/signin-oidc application/x-www-form-urlencoded 5297
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: Cookies signed in.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 184.9938ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44331/  
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: Identity.Application was not authenticated. Failure message: Unprotect ticket failed
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Index", controller = "Home", page = "", area = ""}. Executing action TestApplication.Controllers.HomeController.Index (TestApplication)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: AuthenticationScheme: oidc was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action TestApplication.Controllers.HomeController.Index (TestApplication) in 15.4912ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 29.286ms 302 
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:44331/signin-oidc application/x-www-form-urlencoded 5297
-- and it starts all over again

Does anyone have a clue what I'm doing wrong?

Here's my Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration, IHostingEnvironment environment)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(environment.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{environment.EnvironmentName}.json", optional: true);

        builder.AddEnvironmentVariables();
        Configuration = builder.Build();            
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        services.AddTransient<ApiService>();
        services.AddSingleton(Configuration);
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => false;
            options.MinimumSameSitePolicy = SameSiteMode.None;                       
        });


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

            options.Authority = 'https://localhost:44350; 
            options.RequireHttpsMetadata = true;

            options.ClientId = Configuration.GetValue<string>("IdentityServer:ClientId");
            options.ClientSecret = Configuration.GetValue<string>("IdentityServer:ClientSecret");
            options.ResponseType = "code id_token token"

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

            options.Scope.Add("api1");                
            options.Scope.Add("offline_access");
            options.Scope.Add("openid");
            options.Scope.Add("profile");
            options.Scope.Add("email");

            options.TokenValidationParameters.NameClaimType = "name";
            options.TokenValidationParameters.RoleClaimType = "role";

        });

        services.AddMvc(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
            config.Filters.Add(new AuthorizeFilter(policy));
        });

        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore)
            .AddJsonOptions(x => x.SerializerSettings.NullValueHandling = NullValueHandling.Ignore);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseAuthentication();
        app.UseHttpsRedirection();
        app.UseCookiePolicy();


        app.UseMvc(routes =>
        {
            routes.MapRoute(
               name: "areas",
               template: "{area:exists}/{controller}/{action}/{id?}");

            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

    }
}

回答1:


On Identity Server side , you can create Profile Service to make IDS4 include role claim when issuing tokens . Then on client side you can map the role claim from your JWT Token to your claim principle . You can refer to code sample from here .

To manage users or roles , you can provide API endpoint in your identity server4 application , or create a new application as another resource to manage your database , you client application will acquire access token for accessing you new application form Identity Server 4 , send request by appending token to HTTP Authorization header for management API calls .



来源:https://stackoverflow.com/questions/54957434/asp-net-identity-in-mvc-client-using-identityserver-causes-loop

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