【问题标题】:Including a Subdirectory in URI - ASP.NET Core 3.1 Identity Server在 URI 中包含子目录 - ASP.NET Core 3.1 Identity Server
【发布时间】:2020-04-20 16:30:19
【问题描述】:

我正在尝试向我的身份服务器添加一个子目录,以便可以将其与 nginx 一起使用。

请注意,这是一个带有 UI 的身份服务器,请参阅 (quickstart ui)

在仔细阅读身份服务器的github 问题后,我设法找到了实际添加子目录的代码。

这是我的配置:

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

    app.Map("/auth", app =>
    {
        app.UseRouting();

        app.UseStaticFiles();

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

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


        app.UseIdentityServer();
    });           
}

但是,当我导航到 http://xxx:8888/auth/account/login 并尝试登录并接收身份 cookie 时,URL 保持不变,并且我看到一个空白屏幕并且没有 cookie。应该发生的是,我应该被重定向回主页并登录特定用户。

这似乎只有在我添加子目录时才会发生。

请注意,众所周知的端点在使用/auth 获取password 或resource owner 的访问令牌时工作正常。

这是我的配置服务,这里有什么遗漏吗?:

public void ConfigureServices(IServiceCollection services)
{
    string connectionString = Configuration.GetConnectionString("AzureConnection");
    var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());
    });

    services.AddControllersWithViews().AddRazorRuntimeCompilation();

    services.AddRazorPages()
        .AddRazorPagesOptions(options => 
            {                        
                options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
            });

    services.AddDbContext<IdentityDbContext>(options => options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)));
    services.AddDbContext<ConfigurationDbContext>(options => options.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)));

    services.AddIdentity<ApplicationUser, IdentityRole>(options =>
    {
        options.SignIn.RequireConfirmedEmail = true;
    })
        .AddEntityFrameworkStores<IdentityDbContext>()
        .AddDefaultTokenProviders();

    services.AddAuthentication()
        .AddOpenIdConnect("azuread", "Azure AD", options => Configuration.Bind("AzureAd", options));

    services.Configure<OpenIdConnectOptions>("azuread", options =>
    {
        options.GetClaimsFromUserInfoEndpoint = true;
        options.SaveTokens = true;
        options.Scope.Add("openid");
        options.Scope.Add("profile");
        options.Scope.Add("email");
        options.Events = new OpenIdConnectEvents()
        {
            OnRedirectToIdentityProviderForSignOut = context =>
            {
                context.HandleResponse();
                context.Response.Redirect("/Account/Logout");
                return Task.FromResult(0);
            }
        };
    });

    var builder = services.AddIdentityServer(options =>
    {
        options.IssuerUri = "http://xxx:8888"; 
        options.PublicOrigin = "http://xxx:8888";

        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
        options.UserInteraction.LoginUrl = "/Account/Login";
        options.UserInteraction.LogoutUrl = "/Account/Logout";

        options.Authentication = new IdentityServer4.Configuration.AuthenticationOptions()
        {
            CookieLifetime = TimeSpan.FromHours(10), // ID server cookie timeout set to 10 hours
            CookieSlidingExpiration = true
        };
    })
    .AddConfigurationStore(options =>
    {
        options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
    })
    .AddOperationalStore(options =>
    {
        options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
        options.EnableTokenCleanup = true;
    })
    .AddAspNetIdentity<ApplicationUser>();
}

这实际上可以根据请求在具有公共 URL 的 VM 上进行测试。

【问题讨论】:

    标签: asp.net-core identityserver4


    【解决方案1】:

    我的第一个观察是您应该将各种 app.UseXXXX 语句放在 App.Map 方法之前。我还在下面的代码中重新排列了中间件。

    public void Configure(IApplicationBuilder app)
    {
        if (Environment.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseStaticFiles();
    
        app.UseRouting();
    
        app.UseIdentityServer();
        app.UseAuthorization();
    
        app.Map("/auth", app =>
        {
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
                endpoints.MapRazorPages();
            });
    });           
    

    }

    此外,UseIdentityServer 包含对 UseAuthentication 的调用,因此没有必要同时拥有。

    【讨论】:

    • 感谢您的回答。自从这篇文章以来,我已经为nginx 添加了转发标头中间件,那么这也会超出Map 方法吗?此外,我在一定程度上解决了子目录问题,但删除了Login 和Logout 方法在AccountController.cs 中使用的[ValidateAntiForgeryToken] 属性。此外,我必须为所有 css 和 javascript 源添加一个基本路径,以使所有内容看起来和发挥应有的作用。
    • 您应该将大多数中间件放在 Map 方法之外,因为关键是对系统的大多数请求都应该通过它们,然后它们将对应用程序的所有请求处于活动状态。 ValidateAntiForgeryToken 方法仅与您的 POST/PUT 方法相关,与您的普通 GET 方法无关。最后一个问题是为什么你需要使用 App.App?我会删除它并只使用 app.UseEndpoints(...)。方法。
    • 我可以只使用app.UsePathBase(new PathString("/auth"))而不打扰Map,但我需要一个子目录的原因是因为nginx,但我仍然担心必须注释掉@987654334 @ 在 POST Login 和 Logout 方法上,因为让 IDS 运行一个简单的子目录感觉很麻烦。您是否知道为什么需要省略这些才能使其正常工作。
    • 可能设置cookie时需要设置Path属性?设置时检查 cookie,也许它们仅限于 /auth 路径而不是其他路径?
    猜你喜欢
    • 1970-01-01
    • 2021-03-06
    • 2020-11-28
    • 1970-01-01
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 2020-08-02
    相关资源
    最近更新 更多