我可以使用 HTTP 而不是 HTTPS 来托管 MVC 客户端以使用 IdentityServer 吗?

Can I use HTTP instead of HTTPS to host MVC client to work with IdentityServer?

我的快速启动程序在我的本地测试环境中运行:一个 MVC 客户端通过 IdentityServer 访问 API。这都是使用 HTTPS 和 self-host (Kestrel) 进行的设置。我想知道的是 - 在使用 IdentityServer 时,我可以在 HTTP 而不是 HTTPS 中托管 MVC 吗?当我将 MVC 从 https://localhost:5009 更改为 http://localhost:5008(在几个地方)后,如果我将所有各方更改为使用 HTTP 或仅使用 MVC 而将其余部分保留为 HTTPS,这似乎并不重要,应用程序因错误 "invalid redirect uri".
而失败 我是不是遗漏了什么,或者这只是不允许的事情?

您可以 运行 在开发期间很好地通过 HTTP,但在生产中您应该始终尝试使用 HTTPS。

您收到的错误是因为 IdentityServer 中客户端定义中的重定向URL与您客户端的url不匹配:

RedirectUris =
{
    "https://localhost:5001/...."
},

如果您想在定义 OpenIDConnect 选项时使用 HTTP,还建议在客户端中将此设置为 false。

    /// <summary>
    /// Gets or sets if HTTPS is required for the metadata address or authority.
    /// The default is true. This should be disabled only in development environments.
    /// </summary>
    public bool RequireHttpsMetadata { get; set; } = true;

如果您设法进入 IdentityServer 登录页面,那么在 URL 中您会发现实际发送到 IdentityServer 的重定向URL。或者使用 fiddler 捕获请求以查看传递给 identityserver 的 requestUrl 是什么。

当我查看屏幕截图时,allowedRedirectURis 中有端口 5009,请求中有 5008。

这是我的 MVC Startup

    public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    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.AddControllersWithViews();
        JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            // The default is true. This should be disabled only in development environments!!!
            options.RequireHttpsMetadata = false;

            options.Authority = "https://localhost:5005";

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

            options.SaveTokens = true;

            options.Scope.Add("profile"); 
            options.Scope.Add("email"); 
            options.GetClaimsFromUserInfoEndpoint = true; 

            options.Scope.Add("MyAPI"); 
            options.Scope.Add("offline_access"); 
        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }
        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}")
                .RequireAuthorization(); 
        });
    }
}

这是 IdentityServer 的启动

public class Startup
{
    public IWebHostEnvironment Environment { get; }
    public IConfiguration Configuration { get; }

    public Startup(IWebHostEnvironment environment, IConfiguration configuration)
    {
        Environment = environment;
        Configuration = configuration;
    }

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

        var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

        var connstr = Configuration.GetConnectionString("MyIDSConnection");
        services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connstr));

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

        var builder = services.AddIdentityServer(options =>
        {
            options.Events.RaiseErrorEvents = true;
            options.Events.RaiseInformationEvents = true;
            options.Events.RaiseFailureEvents = true;
            options.Events.RaiseSuccessEvents = true;

            options.EmitStaticAudienceClaim = true;
        })
            .AddAspNetIdentity<ApplicationUser>()
            .AddConfigurationStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(connstr,
                    sql => sql.MigrationsAssembly(migrationsAssembly));
            })
            .AddOperationalStore(options =>
            {
                options.ConfigureDbContext = b => b.UseSqlServer(connstr,
                    sql => sql.MigrationsAssembly(migrationsAssembly));
            });

        // not recommended for production - you need to store your key material somewhere secure
        builder.AddDeveloperSigningCredential();
        //services.AddIdentityServer().AddSigningCredential(
        //    new X509Certificate2(Path.Combine(_environment.ContentRootPath, "certs", "IdentityServer4Auth.pfx")));

        services.AddAuthentication()
            .AddGoogle(options =>
            {
                options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

                // register your IdentityServer with Google at https://console.developers.google.com
                // enable the Google+ API
                // set the redirect URI to https://localhost:5001/signin-google
                options.ClientId = "";
                options.ClientSecret = "";
            });
    }

    public void Configure(IApplicationBuilder app)
    {
        if (Environment.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }

        // uncomment if use MVC
        app.UseStaticFiles();
        app.UseRouting();

        // Add IdentityServer to the pipeline
        // UseIdentityServer includes a call to UseAuthentication, so it’s not necessary to have both
        app.UseIdentityServer();
        // uncomment if use MVC
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
        });
    }

    private void InitializeDatabase(IApplicationBuilder app)
    {
        using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
        {
            serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
            var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
            context.Database.Migrate();
            serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>().Database.Migrate();

            if (!context.Clients.Any())
            {
                foreach (var client in Config.Clients)
                {
                    context.Clients.Add(client.ToEntity());
                }
                context.SaveChanges();
            }

            if (!context.IdentityResources.Any())
            {
                foreach (var resource in Config.IdentityResources)
                {
                    context.IdentityResources.Add(resource.ToEntity());
                }
                context.SaveChanges();
            }

            if (!context.ApiScopes.Any())
            {
                foreach (var resource in Config.ApiScopes)
                {
                    context.ApiScopes.Add(resource.ToEntity());
                }
                context.SaveChanges();
            }
        }
    }
}

这是启动时的 IdentityServer 控制台 window

这是启动时的 MVC 控制台 window