You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 6中基于IdentityServer 6实现SPA首次加载前身份认证问题

问题描述

我尝试使用IdentityServer 6搭建认证服务器,为不同域名的多个SPA应用提供身份认证服务。在.NET 3.1+IdentityServer 4环境中,首次访问SPA时可正常跳转至认证服务器的登录页,但在.NET 6+IdentityServer 6环境下,SPA会直接加载首页而不跳转;访问带有[Authorize]特性的资源时,返回200状态码及登录URL,但不会自动跳转至登录页。我参考了相关方案,但无法在新版本中实现预期效果,以下是Angular SPA的配套后端代码:

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Serilog;

Log.Logger = new LoggerConfiguration()
    .WriteTo.Console()
    .CreateBootstrapLogger();

Log.Information("Starting up");

try
{
    var builder = WebApplication.CreateBuilder(args);

    builder.Host.UseSerilog((ctx, lc) => lc
        .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}")
        .Enrich.FromLogContext()
        .ReadFrom.Configuration(ctx.Configuration));


    // Add services to the container.

    builder.Services.AddControllersWithViews();

    builder.Services.AddAuthentication(authenticationOptions =>
    {
        authenticationOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        authenticationOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
    })
        .AddCookie("cookie")
        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, openIdConnectOptions =>
        {
            openIdConnectOptions.Authority = builder.Configuration["InteractiveServiceSettings:AuthorityUrl"];
            openIdConnectOptions.ClientId = builder.Configuration["InteractiveServiceSettings:ClientId"];
            openIdConnectOptions.ClientSecret = builder.Configuration["InteractiveServiceSettings:ClientSecret"];
            openIdConnectOptions.Scope.Add(builder.Configuration["InteractiveServiceSettings:Scopes:0"]);
            openIdConnectOptions.GetClaimsFromUserInfoEndpoint = true;
            openIdConnectOptions.ResponseType = "code";
            openIdConnectOptions.SaveTokens = true;
            openIdConnectOptions.UsePkce = true;
            openIdConnectOptions.ResponseMode = "query";
            openIdConnectOptions.RequireHttpsMetadata = false;
            
        });

    builder.Services.AddAuthorization();

    var app = builder.Build();

    // Configure the HTTP request pipeline.
    if (!app.Environment.IsDevelopment())
    {
        // 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.UseCors("AllowAll");
    app.Use(async (context, next) =>
    {
        if (!(context.User.Identity.IsAuthenticated && context.Request.Path != "/signin-oidc"))
        {
            await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
        }
        else
        {
            await next();
        }
    });

   
    //app.UseEndpoints(endpoints =>
    //{
    //    endpoints.MapControllers();
    //    //fallback to SPA
    //    //endpoints.MapFallbackToFile("index.html");
    //    endpoints.MapFallback(CreateRequestDelegate(endpoints, "index.html"));
    //    //local function
    //    RequestDelegate CreateRequestDelegate(IEndpointRouteBuilder endpoints, string filePath)
    //    {
    //        var app = endpoints.CreateApplicationBuilder();
    //        //Use Cookie authentication to secure angular index.html file
    //        app.Use(async (context, next) =>
    //        {
    //            bool isAuth = false;
    //            //TODO: run logic to check authentication
    //            //....

    //            if (!isAuth)
    //            {
    //                await context.ChallengeAsync(OpenIdConnectDefaults.AuthenticationScheme);
    //            }
    //            else
    //            {
    //                await next.Invoke();
    //            }

    //        });
    //        //to SPA index.html
    //        app.Use(next => context =>
    //        {
    //            context.Request.Path = "/" + filePath;
    //            // Set endpoint to null so the static files middleware will handle the request.
    //            context.SetEndpoint(null);
    //            return next(context);
    //        });
    //        app.UseStaticFiles();
    //        return app.Build();
    //    }
    //});
    
    app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");


    app.MapFallbackToFile("index.html");

    app.Run();
}
catch (Exception ex)
{
    Log.Fatal(ex, "Unhandled exception");
}
finally
{
    Log.Information("Shut down complete");
    Log.CloseAndFlush();
}

内容的提问来源于stack exchange,提问作者Raja Somu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 03:36:18